From 7b89e68d18597f95f6d9a1405505df350076b942 Mon Sep 17 00:00:00 2001 From: Vignesh Natarajan Date: Sat, 14 Feb 2026 19:06:19 -0800 Subject: [PATCH] fix (cron): skip startup replay for interrupted running jobs --- src/cron/service/ops.ts | 4 +++- src/cron/service/timer.ts | 9 ++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/cron/service/ops.ts b/src/cron/service/ops.ts index 7a2aab6b724..1df1dfc95e3 100644 --- a/src/cron/service/ops.ts +++ b/src/cron/service/ops.ts @@ -22,6 +22,7 @@ export async function start(state: CronServiceState) { } await ensureLoaded(state, { skipRecompute: true }); const jobs = state.store?.jobs ?? []; + const startupInterruptedJobIds = new Set(); for (const job of jobs) { if (typeof job.state.runningAtMs === "number") { state.deps.log.warn( @@ -29,9 +30,10 @@ export async function start(state: CronServiceState) { "cron: clearing stale running marker on startup", ); job.state.runningAtMs = undefined; + startupInterruptedJobIds.add(job.id); } } - await runMissedJobs(state); + await runMissedJobs(state, { skipJobIds: startupInterruptedJobIds }); recomputeNextRuns(state); await persist(state); armTimer(state); diff --git a/src/cron/service/timer.ts b/src/cron/service/timer.ts index e708a4ea39d..f0354958f52 100644 --- a/src/cron/service/timer.ts +++ b/src/cron/service/timer.ts @@ -357,11 +357,15 @@ function findDueJobs(state: CronServiceState): CronJob[] { }); } -export async function runMissedJobs(state: CronServiceState) { +export async function runMissedJobs( + state: CronServiceState, + opts?: { skipJobIds?: ReadonlySet }, +) { if (!state.store) { return; } const now = state.deps.nowMs(); + const skipJobIds = opts?.skipJobIds; const missed = state.store.jobs.filter((j) => { if (!j.state) { j.state = {}; @@ -369,6 +373,9 @@ export async function runMissedJobs(state: CronServiceState) { if (!j.enabled) { return false; } + if (skipJobIds?.has(j.id)) { + return false; + } if (typeof j.state.runningAtMs === "number") { return false; }