fix(stability): patch regex retries and timeout abort handling

This commit is contained in:
Frank Yang
2026-02-22 00:12:22 -08:00
committed by Peter Steinberger
parent 99a2f5379e
commit 1051f42f96
15 changed files with 294 additions and 19 deletions

View File

@@ -683,6 +683,55 @@ describe("Cron issue regressions", () => {
expect(job?.state.lastStatus).toBe("ok");
});
it("aborts isolated runs when cron timeout fires", async () => {
vi.useRealTimers();
const store = await makeStorePath();
const scheduledAt = Date.parse("2026-02-15T13:00:00.000Z");
const cronJob = createIsolatedRegressionJob({
id: "abort-on-timeout",
name: "abort timeout",
scheduledAt,
schedule: { kind: "at", at: new Date(scheduledAt).toISOString() },
payload: { kind: "agentTurn", message: "work", timeoutSeconds: 0.01 },
state: { nextRunAtMs: scheduledAt },
});
await writeCronJobs(store.storePath, [cronJob]);
let now = scheduledAt;
let observedAbortSignal: AbortSignal | undefined;
const state = createCronServiceState({
cronEnabled: true,
storePath: store.storePath,
log: noopLogger,
nowMs: () => now,
enqueueSystemEvent: vi.fn(),
requestHeartbeatNow: vi.fn(),
runIsolatedAgentJob: vi.fn(async ({ abortSignal }) => {
observedAbortSignal = abortSignal;
await new Promise<void>((resolve) => {
if (!abortSignal) {
return;
}
if (abortSignal.aborted) {
resolve();
return;
}
abortSignal.addEventListener("abort", () => resolve(), { once: true });
});
now += 5;
return { status: "ok" as const, summary: "late" };
}),
});
await onTimer(state);
expect(observedAbortSignal).toBeDefined();
expect(observedAbortSignal?.aborted).toBe(true);
const job = state.store?.jobs.find((entry) => entry.id === "abort-on-timeout");
expect(job?.state.lastStatus).toBe("error");
expect(job?.state.lastError).toContain("timed out");
});
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({