mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-08 06:54:24 +00:00
Cron: preserve due jobs after manual runs (#23994)
This commit is contained in:
@@ -561,6 +561,46 @@ describe("Cron issue regressions", () => {
|
||||
await runFinished.promise;
|
||||
// Barrier for final persistence before cleanup.
|
||||
await cron.list({ includeDisabled: true });
|
||||
cron.stop();
|
||||
});
|
||||
|
||||
it("does not advance unrelated due jobs after manual cron.run", async () => {
|
||||
const store = await makeStorePath();
|
||||
const nowMs = Date.now();
|
||||
const dueNextRunAtMs = nowMs - 1_000;
|
||||
|
||||
await writeCronJobs(store.storePath, [
|
||||
createIsolatedRegressionJob({
|
||||
id: "manual-target",
|
||||
name: "manual target",
|
||||
scheduledAt: nowMs,
|
||||
schedule: { kind: "at", at: new Date(nowMs + 3_600_000).toISOString() },
|
||||
payload: { kind: "agentTurn", message: "manual target" },
|
||||
state: { nextRunAtMs: nowMs + 3_600_000 },
|
||||
}),
|
||||
createIsolatedRegressionJob({
|
||||
id: "unrelated-due",
|
||||
name: "unrelated due",
|
||||
scheduledAt: nowMs,
|
||||
schedule: { kind: "cron", expr: "*/5 * * * *", tz: "UTC" },
|
||||
payload: { kind: "agentTurn", message: "unrelated due" },
|
||||
state: { nextRunAtMs: dueNextRunAtMs },
|
||||
}),
|
||||
]);
|
||||
|
||||
const cron = await startCronForStore({
|
||||
storePath: store.storePath,
|
||||
cronEnabled: false,
|
||||
runIsolatedAgentJob: createDefaultIsolatedRunner(),
|
||||
});
|
||||
|
||||
const runResult = await cron.run("manual-target", "force");
|
||||
expect(runResult).toEqual({ ok: true, ran: true });
|
||||
|
||||
const jobs = await cron.list({ includeDisabled: true });
|
||||
const unrelated = jobs.find((entry) => entry.id === "unrelated-due");
|
||||
expect(unrelated).toBeDefined();
|
||||
expect(unrelated?.state.nextRunAtMs).toBe(dueNextRunAtMs);
|
||||
|
||||
cron.stop();
|
||||
});
|
||||
|
||||
@@ -297,7 +297,10 @@ export async function run(state: CronServiceState, id: string, mode?: "due" | "f
|
||||
emit(state, { jobId: job.id, action: "removed" });
|
||||
}
|
||||
|
||||
recomputeNextRuns(state);
|
||||
// Manual runs should not advance other due jobs without executing them.
|
||||
// Use maintenance-only recompute to repair missing values while
|
||||
// preserving existing past-due nextRunAtMs entries for future timer ticks.
|
||||
recomputeNextRunsForMaintenance(state);
|
||||
await persist(state);
|
||||
armTimer(state);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user