fix(cron): enforce timeout for manual cron runs

This commit is contained in:
Peter Steinberger
2026-02-22 19:51:54 +01:00
parent 8bf3c37c6c
commit c3bb723673
3 changed files with 83 additions and 1 deletions

View File

@@ -13,6 +13,7 @@ import { locked } from "./locked.js";
import type { CronServiceState } from "./state.js";
import { ensureLoaded, persist, warnIfDisabled } from "./store.js";
import {
DEFAULT_JOB_TIMEOUT_MS,
applyJobResult,
armTimer,
emit,
@@ -247,8 +248,40 @@ export async function run(state: CronServiceState, id: string, mode?: "due" | "f
status: "error";
error: string;
};
const configuredTimeoutMs =
prepared.executionJob.payload.kind === "agentTurn" &&
typeof prepared.executionJob.payload.timeoutSeconds === "number"
? Math.floor(prepared.executionJob.payload.timeoutSeconds * 1_000)
: undefined;
const jobTimeoutMs =
configuredTimeoutMs !== undefined
? configuredTimeoutMs <= 0
? undefined
: configuredTimeoutMs
: DEFAULT_JOB_TIMEOUT_MS;
try {
coreResult = await executeJobCore(state, prepared.executionJob);
const runAbortController = typeof jobTimeoutMs === "number" ? new AbortController() : undefined;
coreResult =
typeof jobTimeoutMs === "number"
? await (async () => {
let timeoutId: NodeJS.Timeout | undefined;
try {
return await Promise.race([
executeJobCore(state, prepared.executionJob, runAbortController?.signal),
new Promise<never>((_, reject) => {
timeoutId = setTimeout(() => {
runAbortController?.abort(new Error("cron: job execution timed out"));
reject(new Error("cron: job execution timed out"));
}, jobTimeoutMs);
}),
]);
} finally {
if (timeoutId) {
clearTimeout(timeoutId);
}
}
})()
: await executeJobCore(state, prepared.executionJob);
} catch (err) {
coreResult = { status: "error", error: String(err) };
}