fix(cron): prevent every schedule from firing in infinite loop
When anchorMs is not provided (always in production), the schedule computed nextRunAtMs as nowMs, causing jobs to fire immediately and repeatedly instead of at the configured interval. - Change nowMs <= anchor to nowMs < anchor to prevent early return - Add Math.max(1, ...) to ensure steps is always at least 1 - Add test for anchorMs not provided case
This commit is contained in:
@@ -23,4 +23,12 @@ describe("cron schedule", () => {
|
||||
);
|
||||
expect(next).toBe(anchor + 30_000);
|
||||
});
|
||||
|
||||
it("computes next run for every schedule when anchorMs is not provided", () => {
|
||||
const now = Date.parse("2025-12-13T00:00:00.000Z");
|
||||
const next = computeNextRunAtMs({ kind: "every", everyMs: 30_000 }, now);
|
||||
|
||||
// Should return nowMs + everyMs, not nowMs (which would cause infinite loop)
|
||||
expect(next).toBe(now + 30_000);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,9 +12,9 @@ export function computeNextRunAtMs(
|
||||
if (schedule.kind === "every") {
|
||||
const everyMs = Math.max(1, Math.floor(schedule.everyMs));
|
||||
const anchor = Math.max(0, Math.floor(schedule.anchorMs ?? nowMs));
|
||||
if (nowMs <= anchor) return anchor;
|
||||
if (nowMs < anchor) return anchor;
|
||||
const elapsed = nowMs - anchor;
|
||||
const steps = Math.floor((elapsed + everyMs - 1) / everyMs);
|
||||
const steps = Math.max(1, Math.floor((elapsed + everyMs - 1) / everyMs));
|
||||
return anchor + steps * everyMs;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user