← Back to PRs

#12448: fix: prevent cron list/status from silently skipping due jobs

by Yida-Dev open 2026-02-09 08:08 View on GitHub →
stale
## Summary Fixes #12440 When `cron list` or `cron status` is called after a job's scheduled time but before the 60-second timer fires, `recomputeNextRuns()` advances `nextRunAtMs` to the next cycle — effectively skipping the due run without executing it. **Root cause:** `recomputeNextRuns()` treats past-due jobs (`now >= nextRunAtMs`) the same as jobs with missing `nextRunAtMs` — it recomputes both. For `start()` this is correct because `runMissedJobs()` runs first, but `list()` and `status()` never execute missed jobs before calling `recomputeNextRuns()`. **Fix:** Add a `preserveDue` option to `recomputeNextRuns()` that skips past-due jobs so the timer can still pick them up. `list()` and `status()` pass `{ preserveDue: true }` while `start()`, `onTimer()`, and `add()` retain the default behaviour. ### Changed files - `src/cron/service/jobs.ts` — `recomputeNextRuns()` accepts optional `{ preserveDue: true }` to leave past-due `nextRunAtMs` untouched - `src/cron/service/ops.ts` — `status()` and `list()` pass `{ preserveDue: true }` - `src/cron/service/jobs.test.ts` — regression tests covering the new behaviour ## Test plan - [x] New unit tests: `recomputeNextRuns` with `preserveDue: true` leaves past-due jobs untouched - [x] New unit tests: `recomputeNextRuns` without `preserveDue` advances past-due jobs (existing behaviour) - [x] New unit tests: `preserveDue: true` still fills in missing `nextRunAtMs` - [x] Full test suite passes (975/975, 1 pre-existing failure unrelated to cron) <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR changes cron’s `recomputeNextRuns()` to accept an optional `preserveDue` flag. When set, past-due jobs (`now >= nextRunAtMs`) are left untouched rather than being recomputed forward, preventing `cron list` / `cron status` from accidentally “skipping” a due run before the timer fires. `status()` and `list()` now call `recomputeNextRuns(state, { preserveDue: true })`, while the scheduler paths (`start`, timer, add) keep the default behavior. A new unit test file (`src/cron/service/jobs.test.ts`) was added to cover both behaviors (default recompute advances past-due jobs; `preserveDue` keeps them due; `preserveDue` still fills missing `nextRunAtMs`). <h3>Confidence Score: 3/5</h3> - Behavioral change looks correct, but the added tests likely won’t compile as written without completing CronServiceState deps stubs. - The core logic change is small and targeted (only gates recomputation when due + preserveDue), and the call sites are appropriate (list/status). The main merge-blocker risk is build/test failure from the new test helper constructing an incomplete CronServiceState (and secondarily, using a fixed /tmp path that could become an FS write if a codepath changes). - src/cron/service/jobs.test.ts <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs