mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 02:52:43 +00:00
Cron: respect aborts in main wake-now retries (#23967)
* Cron: respect aborts in main wake-now retries * Changelog: add main-session cron abort retry fix note * Cron tests: format post-rebase conflict resolution
This commit is contained in:
@@ -3,12 +3,13 @@ import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { HeartbeatRunResult } from "../infra/heartbeat-wake.js";
|
||||
import * as schedule from "./schedule.js";
|
||||
import { CronService } from "./service.js";
|
||||
import { createDeferred, createRunningCronServiceState } from "./service.test-harness.js";
|
||||
import { computeJobNextRunAtMs } from "./service/jobs.js";
|
||||
import { createCronServiceState, type CronEvent } from "./service/state.js";
|
||||
import { onTimer, runMissedJobs } from "./service/timer.js";
|
||||
import { executeJobCore, onTimer, runMissedJobs } from "./service/timer.js";
|
||||
import type { CronJob, CronJobState } from "./types.js";
|
||||
|
||||
const noopLogger = {
|
||||
@@ -859,6 +860,55 @@ describe("Cron issue regressions", () => {
|
||||
expect(job?.state.lastError).toContain("timed out");
|
||||
});
|
||||
|
||||
it("respects abort signals while retrying main-session wake-now heartbeat runs", async () => {
|
||||
vi.useRealTimers();
|
||||
const abortController = new AbortController();
|
||||
const runHeartbeatOnce = vi.fn(
|
||||
async (): Promise<HeartbeatRunResult> => ({
|
||||
status: "skipped",
|
||||
reason: "requests-in-flight",
|
||||
}),
|
||||
);
|
||||
const enqueueSystemEvent = vi.fn();
|
||||
const requestHeartbeatNow = vi.fn();
|
||||
const mainJob: CronJob = {
|
||||
id: "main-abort",
|
||||
name: "main abort",
|
||||
enabled: true,
|
||||
createdAtMs: Date.now(),
|
||||
updatedAtMs: Date.now(),
|
||||
schedule: { kind: "every", everyMs: 60_000, anchorMs: Date.now() },
|
||||
sessionTarget: "main",
|
||||
wakeMode: "now",
|
||||
payload: { kind: "systemEvent", text: "tick" },
|
||||
state: {},
|
||||
};
|
||||
const state = createCronServiceState({
|
||||
cronEnabled: true,
|
||||
storePath: "/tmp/openclaw-cron-abort-test/jobs.json",
|
||||
log: noopLogger,
|
||||
nowMs: () => Date.now(),
|
||||
enqueueSystemEvent,
|
||||
requestHeartbeatNow,
|
||||
runHeartbeatOnce,
|
||||
wakeNowHeartbeatBusyMaxWaitMs: 30,
|
||||
wakeNowHeartbeatBusyRetryDelayMs: 5,
|
||||
runIsolatedAgentJob: createDefaultIsolatedRunner(),
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
abortController.abort();
|
||||
}, 10);
|
||||
|
||||
const result = await executeJobCore(state, mainJob, abortController.signal);
|
||||
|
||||
expect(result.status).toBe("error");
|
||||
expect(result.error).toContain("timed out");
|
||||
expect(enqueueSystemEvent).toHaveBeenCalledTimes(1);
|
||||
expect(runHeartbeatOnce).toHaveBeenCalled();
|
||||
expect(requestHeartbeatNow).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("retries cron schedule computation from the next second when the first attempt returns undefined (#17821)", () => {
|
||||
const scheduledAt = Date.parse("2026-02-15T13:00:00.000Z");
|
||||
const cronJob = createIsolatedRegressionJob({
|
||||
|
||||
Reference in New Issue
Block a user