Fix cron worker minute cadence (#324)

Replace drifting cron loops with persistent cadence-tracked workers and CI-verifiable Compose wiring.
This commit is contained in:
Jeppe B
2026-07-27 18:16:09 +02:00
committed by GitHub
parent 6e24718c1f
commit 8d8f0eccce
9 changed files with 156 additions and 24 deletions
+27 -6
View File
@@ -227,10 +227,15 @@ class cron_scheduler
"UPDATE cron_task_state SET current_run_id = $run_id WHERE task_id = " . $this->sql($definition->id)
);
return $this->executeClaimedRun($definition, $run_id, $started);
return $this->executeClaimedRun($definition, $run_id, $started, $scheduled_for);
}
private function executeClaimedRun(cron_task_definition $definition, int $run_id, float $started): array
private function executeClaimedRun(
cron_task_definition $definition,
int $run_id,
float $started,
?string $scheduled_for = null
): array
{
$status = 'succeeded';
$summary = [];
@@ -272,7 +277,7 @@ class cron_scheduler
$completed_at = date('Y-m-d H:i:s', (int)$completed);
$this->completeRun($run_id, $status, $completed_at, $duration_ms, $summary, $error_message);
$this->releaseLock($definition, $status, $error_message, $completed_at);
$this->releaseLock($definition, $status, $error_message, $completed_at, $scheduled_for);
return $this->publicRun($this->fetchOne("SELECT * FROM cron_task_runs WHERE id = $run_id") ?? []);
}
@@ -441,7 +446,12 @@ class cron_scheduler
"UPDATE cron_task_state SET current_run_id = $run_id WHERE task_id = " . $this->sql($definition->id)
);
return $this->executeClaimedRun($definition, $run_id, $started);
return $this->executeClaimedRun(
$definition,
$run_id,
$started,
isset($queuedRun['scheduled_for']) ? (string)$queuedRun['scheduled_for'] : null
);
}
private function skipQueuedRun(int $run_id, string $message, ?cron_task_definition $definition = null): void
@@ -479,7 +489,13 @@ class cron_scheduler
);
}
private function releaseLock(cron_task_definition $definition, string $status, ?string $error_message, string $completed_at): void
private function releaseLock(
cron_task_definition $definition,
string $status,
?string $error_message,
string $completed_at,
?string $scheduled_for = null
): void
{
$state = $this->fetchOne("SELECT schedule_json FROM cron_task_state WHERE task_id = " . $this->sql($definition->id));
$schedule = $this->decodeJson($state['schedule_json'] ?? null);
@@ -487,7 +503,12 @@ class cron_scheduler
$schedule = $definition->schedule;
}
$nextRunAt = cron_schedule::nextRunAt($schedule, $completed_at, time());
// Automatic runs stay anchored to their intended schedule slot. Anchoring
// to completion time causes every task to drift by its execution time.
$scheduleAnchor = $scheduled_for !== null && strtotime($scheduled_for) !== false
? $scheduled_for
: $completed_at;
$nextRunAt = cron_schedule::nextRunAt($schedule, $scheduleAnchor, time());
if ($status !== 'succeeded') {
$retrySeconds = min(300, max(60, (int)$schedule['seconds']));
$nextRunAt = date('Y-m-d H:i:s', time() + $retrySeconds);