diff --git a/src/cron/schedule.test.ts b/src/cron/schedule.test.ts index 210e2860a..f38bc6a2d 100644 --- a/src/cron/schedule.test.ts +++ b/src/cron/schedule.test.ts @@ -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); + }); }); diff --git a/src/cron/schedule.ts b/src/cron/schedule.ts index 4c4308da8..bdf92ea13 100644 --- a/src/cron/schedule.ts +++ b/src/cron/schedule.ts @@ -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; }