#8034: fix(cron): run past-due one-shot jobs immediately on startup
stale
Cluster:
Cron Job Management Fixes
Fixes #8016.
## The Problem
When the gateway restarts, any one-shot cron jobs (schedule kind at) that were scheduled for a time *during* the downtime (or before the restart completed) were being ignored. They would sit in the database with enabled: true but never run.
## The Fix
1. Updated `armTimer` in `timer.ts` to handle `nextWakeAtMs` values that are in the past. Instead of potentially failing or setting an invalid timeout, it now clamps the delay to `0`, forcing immediate execution on the next tick.
2. Verified `computeJobNextRunAtMs` continues to return the original `atMs` for incomplete jobs, ensuring they remain 'due'.
## Verification
- Created a one-shot job scheduled for 2 minutes in the future.
- Stopped the gateway.
- Waited 5 minutes (so the job is now past due).
- Restarted the gateway.
- **Result:** The job now executes immediately upon startup.
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR fixes missed one-shot (`schedule.kind === "at"`) cron executions after gateway restarts by changing `armTimer` to treat “past-due” wake times as an immediate tick: it now clamps negative delays to `0` and avoids the prior `if (!nextAt)` early-return that could accidentally skip scheduling when `nextWakeAtMs` was `0`.
`computeJobNextRunAtMs` behavior for one-shot jobs remains effectively the same (it returns `schedule.atMs` until a successful run), so overdue jobs stay due; the key behavioral change is the timer arming logic that now handles past timestamps safely.
<h3>Confidence Score: 4/5</h3>
- This PR is largely safe to merge and addresses the missed one-shot scheduling bug with a small, well-scoped change.
- The change is minimal and targeted (timer arming logic), and it preserves existing next-run calculations for one-shot jobs. Main remaining concern is that `armTimer` now accepts any `number` including `NaN`, which could lead to unexpected immediate ticks if state is corrupted; otherwise behavior looks consistent.
- src/cron/service/timer.ts (guarding against NaN/invalid nextAt); src/cron/service/jobs.ts (comment accuracy).
<!-- greptile_other_comments_section -->
<sub>(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#12747: fix: catch up missed cron-expression job runs on restart
by obin94-commits · 2026-02-09
85.7%
#18925: fix(cron): stagger missed jobs on restart to prevent gateway overload
by rexlunae · 2026-02-17
85.0%
#8379: fix(cron): handle past-due one-shot 'at' jobs that haven't run yet
by Gerrald12312 · 2026-02-04
84.5%
#5428: fix(Cron): prevent one-shot loop on skip
by imshrishk · 2026-01-31
84.4%
#11108: fix(cron): prevent missed jobs from being skipped on timer recompute
by Bentlybro · 2026-02-07
84.4%
#12131: fix(cron): ensure timer callback fires for scheduled jobs
by divol89 · 2026-02-08
84.2%
#10918: fix(cron): add tolerance for timer precision and skip due jobs in r...
by Cherwayway · 2026-02-07
84.2%
#10829: fix: prevent cron scheduler permanent death on transient startup/ru...
by meaadore1221-afk · 2026-02-07
84.0%
#12122: fix(cron): ensure timer callback fires for scheduled jobs
by divol89 · 2026-02-08
83.7%
#12086: fix(cron): ensure timer callback fires for scheduled jobs
by divol89 · 2026-02-08
83.7%