Files
clawdbot/src/cron/schedule.ts
James Groat 7154bc6857 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
2026-01-01 17:30:05 -07:00

30 lines
911 B
TypeScript

import { Cron } from "croner";
import type { CronSchedule } from "./types.js";
export function computeNextRunAtMs(
schedule: CronSchedule,
nowMs: number,
): number | undefined {
if (schedule.kind === "at") {
return schedule.atMs > nowMs ? schedule.atMs : undefined;
}
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;
const elapsed = nowMs - anchor;
const steps = Math.max(1, Math.floor((elapsed + everyMs - 1) / everyMs));
return anchor + steps * everyMs;
}
const expr = schedule.expr.trim();
if (!expr) return undefined;
const cron = new Cron(expr, {
timezone: schedule.tz?.trim() || undefined,
catch: false,
});
const next = cron.nextRun(new Date(nowMs));
return next ? next.getTime() : undefined;
}