Cron: daily jobs catch up when the dispatcher is invoked before their scheduled time, so an old single daily crontab entry still runs them

This commit is contained in:
johnnyq
2026-07-30 18:21:47 -04:00
parent 09a74d6d26
commit 7c5579677d
2 changed files with 19 additions and 7 deletions

View File

@@ -96,9 +96,16 @@ function cronJobClaim($mysqli, array $job): bool
if (!empty($row['cron_job_enabled'])) {
if ($row['cron_job_schedule'] === 'Daily') {
// Due once today's scheduled time has passed, unless we have already run since it
// Due once the most recent scheduled time has passed, unless we already ran since
// it. Before today's time, that most recent occurrence was yesterday's - without
// this, a dispatcher only invoked before the scheduled time (the old single
// "0 2 * * * cron.php" crontab line against a 03:00 job) would never find the job
// due and it would silently never run again.
$threshold = date('Y-m-d') . ' ' . substr((string)$row['cron_job_daily_at'], 0, 5) . ':00';
$scheduled = ($now >= $threshold);
if ($now < $threshold) {
$threshold = date('Y-m-d', strtotime('-1 day')) . ' ' . substr((string)$row['cron_job_daily_at'], 0, 5) . ':00';
}
$scheduled = true;
} else {
// Interval jobs get 30 seconds of slack. cron fires on the minute but a run can
// start a second or two late, and an exact n-minute comparison would then find the

View File

@@ -131,13 +131,18 @@ function cronJobNextRun(array $row): ?string
$last_run = $row['cron_job_last_run_at'];
if ($row['cron_job_schedule'] === 'Daily') {
$today = date('Y-m-d') . ' ' . substr((string)$row['cron_job_daily_at'], 0, 5) . ':00';
if ($last_run === null || $last_run < $today) {
return $today <= date('Y-m-d H:i:s') ? date('Y-m-d H:i:s') : $today;
// The most recent scheduled occurrence: today's, or yesterday's if today's has not
// arrived yet - matching how the dispatcher decides due-ness
$occurrence = date('Y-m-d') . ' ' . substr((string)$row['cron_job_daily_at'], 0, 5) . ':00';
if ($occurrence > date('Y-m-d H:i:s')) {
$occurrence = date('Y-m-d', strtotime('-1 day')) . ' ' . substr((string)$row['cron_job_daily_at'], 0, 5) . ':00';
}
return date('Y-m-d H:i:s', strtotime($today) + 86400);
if ($last_run === null || $last_run < $occurrence) {
return date('Y-m-d H:i:s');
}
return date('Y-m-d H:i:s', strtotime($occurrence) + 86400);
}
if ($last_run === null) {