ddsfds
All checks were successful
Deploy / deploy-staging (push) Successful in 5s
Deploy / deploy-production (push) Has been skipped

This commit is contained in:
2026-05-01 02:22:43 +02:00
parent f7f99bd700
commit a9c64c5d68
3 changed files with 178 additions and 2 deletions

View File

@@ -202,6 +202,101 @@ final class ModuleCronScheduler
return $results;
}
public function runNow(string $moduleName, string $jobName, int $entryIndex): array
{
$task = null;
foreach ($this->statuses($moduleName) as $status) {
if ((string) ($status['job_name'] ?? '') === $jobName && (int) ($status['entry_index'] ?? -1) === $entryIndex) {
$task = $status;
break;
}
}
if (!is_array($task)) {
return [
'task' => $jobName,
'entry_index' => $entryIndex,
'ok' => false,
'message' => 'Cron-Eintrag nicht gefunden.',
];
}
if (!$this->modules->hasFunction($moduleName, (string) $task['callback'])) {
return [
'task' => $jobName,
'entry_index' => $entryIndex,
'ok' => false,
'message' => 'Callback nicht registriert.',
];
}
if (!$this->acquireLock($moduleName, (string) $task['state_key'], (int) $task['lock_minutes'])) {
return [
'task' => $jobName,
'entry_index' => $entryIndex,
'ok' => false,
'message' => 'Cron-Eintrag ist aktuell gesperrt.',
];
}
$startedAt = gmdate('Y-m-d H:i:s');
$timezone = $this->safeTimezone((string) ($task['timezone'] ?? 'UTC'));
$this->persistState($moduleName, (string) $task['state_key'], [
'last_started_at' => $startedAt,
'last_status' => 'running',
'last_message' => 'Manueller Testlauf gestartet.',
]);
try {
$result = $this->modules->call($moduleName, (string) $task['callback'], [
'task' => $task,
'trigger' => 'manual_test',
'started_at' => $startedAt,
'scheduled_for_utc' => null,
'scheduled_for_local' => null,
'timezone' => $timezone->getName(),
]);
$ok = !is_array($result) || !array_key_exists('ok', $result) || !empty($result['ok']);
$skipped = is_array($result) && !empty($result['skipped']);
$message = is_array($result) ? trim((string) ($result['message'] ?? '')) : '';
$finishedAt = gmdate('Y-m-d H:i:s');
$payload = [
'last_finished_at' => $finishedAt,
'last_status' => $skipped ? 'skipped' : ($ok ? 'success' : 'error'),
'last_message' => $message !== '' ? $message : ($ok ? 'Manueller Testlauf erfolgreich.' : 'Manueller Testlauf fehlgeschlagen.'),
'lock_until' => null,
];
if ($ok && !$skipped) {
$payload['last_success_at'] = $finishedAt;
}
$this->persistState($moduleName, (string) $task['state_key'], $payload);
return [
'task' => $jobName,
'entry_index' => $entryIndex,
'ok' => $ok,
'message' => (string) $payload['last_message'],
];
} catch (\Throwable $e) {
$finishedAt = gmdate('Y-m-d H:i:s');
$this->persistState($moduleName, (string) $task['state_key'], [
'last_finished_at' => $finishedAt,
'last_status' => 'error',
'last_message' => $e->getMessage(),
'lock_until' => null,
]);
return [
'task' => $jobName,
'entry_index' => $entryIndex,
'ok' => false,
'message' => $e->getMessage(),
];
}
}
private function jobConfigs(array $definition, array $settings): array
{
$jobs = is_array($settings['scheduler_jobs'] ?? null)

View File

@@ -311,6 +311,11 @@ final class ModuleManager
return $this->cronScheduler()->runDue($name);
}
public function runCronTaskNow(string $name, string $jobName, int $entryIndex): array
{
return $this->cronScheduler()->runNow($name, $jobName, $entryIndex);
}
private function scanModules(): void
{
$this->modules = [];