From 572006f9e10f89338d3a76ef0210b016232ef5e1 Mon Sep 17 00:00:00 2001 From: Josh Wegener Date: Fri, 30 Jan 2026 06:45:23 -0700 Subject: [PATCH] fix(cron): make cron.list/status non-blocking when store is loaded --- src/cron/service/ops.ts | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/cron/service/ops.ts b/src/cron/service/ops.ts index 184d096fb..0cbaf93b5 100644 --- a/src/cron/service/ops.ts +++ b/src/cron/service/ops.ts @@ -39,6 +39,18 @@ export function stop(state: CronServiceState) { } export async function status(state: CronServiceState) { + // Fast path: if the store is already loaded, avoid waiting behind long-running + // cron executions that may hold the cron lock (e.g., isolated agent jobs). + // This keeps `cron.status` responsive. + if (state.store) { + return { + enabled: state.deps.cronEnabled, + storePath: state.deps.storePath, + jobs: state.store.jobs.length ?? 0, + nextWakeAtMs: state.deps.cronEnabled === true ? (nextWakeAtMs(state) ?? null) : null, + }; + } + return await locked(state, async () => { await ensureLoaded(state); return { @@ -51,9 +63,18 @@ export async function status(state: CronServiceState) { } export async function list(state: CronServiceState, opts?: { includeDisabled?: boolean }) { + const includeDisabled = opts?.includeDisabled === true; + + // Fast path: if the store is already loaded, avoid waiting behind long-running + // cron executions that may hold the cron lock (e.g., isolated agent jobs). + // This keeps `cron.list` responsive. + if (state.store) { + const jobs = state.store.jobs.filter((j) => includeDisabled || j.enabled); + return jobs.slice().sort((a, b) => (a.state.nextRunAtMs ?? 0) - (b.state.nextRunAtMs ?? 0)); + } + return await locked(state, async () => { await ensureLoaded(state); - const includeDisabled = opts?.includeDisabled === true; const jobs = (state.store?.jobs ?? []).filter((j) => includeDisabled || j.enabled); return jobs.sort((a, b) => (a.state.nextRunAtMs ?? 0) - (b.state.nextRunAtMs ?? 0)); });