#12747: fix: catch up missed cron-expression job runs on restart
stale
Cluster:
Cron Job Management Fixes
## Summary
Cron-expression jobs (e.g. `0 6 * * *`) silently skip runs when the gateway restarts after the scheduled time. This adds catch-up detection to `recomputeNextRuns()` so missed runs fire immediately on restart.
## Problem
When `recomputeNextRuns()` runs on startup, it calls `computeNextRunAtMs(schedule, now)` which returns the **next future occurrence**. If a daily 6 AM job's gateway restarts at 10 AM, the next occurrence is tomorrow 6 AM — today's run is silently skipped. No error is logged.
In practice, this caused daily morning reports, agent check-ins, and data sweeps to stop firing for 3 consecutive days after a gateway restart.
`every`-interval jobs are unaffected since they recalculate from anchor/now correctly.
## Fix
After computing `nextRunAtMs`, check if a cron-expression job has a scheduled occurrence between `lastRunAtMs` and now that was missed. If so, set `nextRunAtMs = now` to fire the catch-up run immediately.
```typescript
const missedRun = computeNextRunAtMs(job.schedule, job.state.lastRunAtMs);
if (missedRun !== undefined && missedRun <= now) {
job.state.nextRunAtMs = now; // fire catch-up
}
```
## Safety
- Only affects `cron`-expression jobs (not `at` or `every`)
- Only triggers if `lastRunAtMs` exists (job has previously run successfully)
- Only catches up if there's an actual missed occurrence between last run and now
- Weekly Monday jobs won't fire on Wednesday restart unless Monday was actually missed
- Jobs that ran on schedule are unaffected (the computed "next after last" is in the future)
## Testing
Applied this patch to a production deployment and verified:
- Gateway restart correctly detects 4 missed daily jobs and fires them immediately
- Log output confirms catch-up detection with job name, missed timestamp, and last run timestamp
- Jobs that haven't missed a run are unaffected
- `every`-interval and `at` jobs continue working as before
Fixes #12744
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR updates `recomputeNextRuns()` in `src/cron/service/jobs.ts` to detect when cron-expression jobs missed a scheduled occurrence between `lastRunAtMs` and the current startup time, and schedules an immediate run (`nextRunAtMs = now`) to catch up. It logs a structured `info` event when a catch-up is triggered.
The change fits into the cron service’s existing model where `computeJobNextRunAtMs()` determines the next due time per schedule kind, while `recomputeNextRuns()` refreshes persisted job state on startup and periodic ticks.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk.
- The change is narrowly scoped to cron-expression jobs in `recomputeNextRuns()`, uses existing schedule computation (`computeNextRunAtMs`) to detect a missed occurrence, and only triggers when `lastRunAtMs` is present. I did not find any cases where it would create incorrect scheduling for `every` or `at` jobs, or cause repeated immediate re-fires once the runner updates `lastRunAtMs`.
- No files require special attention
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#12443: fix(cron): don't advance past-due jobs that haven't been executed
by rummangeminicode · 2026-02-09
89.2%
#11108: fix(cron): prevent missed jobs from being skipped on timer recompute
by Bentlybro · 2026-02-07
88.0%
#14667: fix: preserve missed cron runs when updating job schedule
by WalterSumbon · 2026-02-12
87.8%
#11857: fix: recompute stale cron nextRunAtMs on gateway restart
by Yida-Dev · 2026-02-08
86.4%
#12982: fix(cron): prevent status/list from advancing overdue job nextRunAtMs
by hclsys · 2026-02-10
86.4%
#9060: Fix: Preserve scheduled cron jobs after gateway restart
by vishaltandale00 · 2026-02-04
85.9%
#23290: fix(cron): use lastRunAtMs for next schedule of interval jobs after...
by SidQin-cyber · 2026-02-22
85.9%
#8034: fix(cron): run past-due one-shot jobs immediately on startup
by FelixFoster · 2026-02-03
85.7%
#13796: fix: skip recomputing nextRunAtMs for running cron jobs (#13739)
by echoVic · 2026-02-11
85.6%
#12303: fix(cron): correct nextRunAtMs calculation and prevent timer stall
by colddonkey · 2026-02-09
84.7%