fix(cron): re-arm one-shot at-jobs when rescheduled after completion (openclaw#28915) thanks @Glucksberg

Verified:
- pnpm install --frozen-lockfile
- pnpm build
- pnpm check
- pnpm test:macmini

Co-authored-by: Glucksberg <80581902+Glucksberg@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
Glucksberg
2026-03-01 23:31:24 -04:00
committed by GitHub
parent 904016b7de
commit 08c35eb13f
3 changed files with 98 additions and 4 deletions

View File

@@ -181,10 +181,6 @@ export function computeJobNextRunAtMs(job: CronJob, nowMs: number): number | und
return isFiniteTimestamp(next) ? next : undefined;
}
if (job.schedule.kind === "at") {
// One-shot jobs stay due until they successfully finish.
if (job.state.lastStatus === "ok" && job.state.lastRunAtMs) {
return undefined;
}
// Handle both canonical `at` (string) and legacy `atMs` (number) fields.
// The store migration should convert atMs→at, but be defensive in case
// the migration hasn't run yet or was bypassed.
@@ -197,6 +193,14 @@ export function computeJobNextRunAtMs(job: CronJob, nowMs: number): number | und
: typeof schedule.at === "string"
? parseAbsoluteTimeMs(schedule.at)
: null;
// One-shot jobs stay due until they successfully finish, but if the
// schedule was updated to a time after the last run, re-arm the job.
if (job.state.lastStatus === "ok" && job.state.lastRunAtMs) {
if (atMs !== null && Number.isFinite(atMs) && atMs > job.state.lastRunAtMs) {
return atMs;
}
return undefined;
}
return atMs !== null && Number.isFinite(atMs) ? atMs : undefined;
}
const next = computeStaggeredCronNextRunAtMs(job, nowMs);