import { describe, expect, it } from "vitest"; import { createMockCronStateForJobs } from "./service.test-harness.js"; import { recomputeNextRuns, recomputeNextRunsForMaintenance } from "./service/jobs.js"; import type { CronJob } from "./types.js";
/** * Regression test for issue #17852: daily cron jobs skip a day (48h jump). * * Root cause: onTimer's results-processing block used the full * recomputeNextRuns which could silently advance a past-due nextRunAtMs * for a job that became due between findDueJobs and the post-execution * locked block — skipping that run and jumping 48h ahead. * * Fix: use recomputeNextRunsForMaintenance in the post-execution block, * which only fills in missing nextRunAtMs values and never overwrites * existing (including past-due) ones.
*/
describe("issue #17852 - daily cron jobs should not skip days", () => { const HOUR_MS = 3_600_000; const DAY_MS = 24 * HOUR_MS;
it("recomputeNextRunsForMaintenance should NOT advance past-due nextRunAtMs by default", () => { // Simulate: job scheduled for 3:00 AM, timer processing happens at 3:00:01 // The job was NOT executed in this tick (e.g., it became due between // findDueJobs and the post-execution block). const threeAM = Date.parse("2026-02-16T03:00:00.000Z"); const now = threeAM + 1_000; // 3:00:01
const job = createDailyThreeAmJob(threeAM);
const state = createMockCronStateForJobs({ jobs: [job], nowMs: now });
recomputeNextRunsForMaintenance(state);
// Maintenance should NOT touch existing past-due nextRunAtMs. // The job should still be eligible for execution on the next timer tick.
expect(job.state.nextRunAtMs).toBe(threeAM);
});
it("recomputeNextRunsForMaintenance can advance expired nextRunAtMs on recovery path when slot already executed", () => { const threeAM = Date.parse("2026-02-16T03:00:00.000Z"); const now = threeAM + 1_000; // 3:00:01
it("full recomputeNextRuns WOULD silently advance past-due nextRunAtMs (the bug)", () => { // This test documents the buggy behavior that caused #17852. // The full recomputeNextRuns sees a past-due nextRunAtMs and advances it // to the next occurrence WITHOUT executing the job. const threeAM = Date.parse("2026-02-16T03:00:00.000Z"); const now = threeAM + 1_000; // 3:00:01
const job = createDailyThreeAmJob(threeAM);
const state = createMockCronStateForJobs({ jobs: [job], nowMs: now });
recomputeNextRuns(state);
// The full recomputeNextRuns advances it to TOMORROW — skipping today's // execution entirely. This is the 48h jump bug: from the previous run // (yesterday 3 AM) to the newly computed next run (tomorrow 3 AM). const tomorrowThreeAM = threeAM + DAY_MS;
expect(job.state.nextRunAtMs).toBe(tomorrowThreeAM);
});
});
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-05-26)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.