fix(cron): set active marker for startup catch-up runs (fixes #91695)#91707
fix(cron): set active marker for startup catch-up runs (fixes #91695)#91707zenglingbiao wants to merge 1 commit into
Conversation
runStartupCatchupCandidate never called markCronJobActive, so the task-registry reconcile misclassified long-running catch-up jobs as lost after 5 minutes and emitted spurious 'Background task lost' messages while the job was still actively running. Add markCronJobActive(candidate.job.id) to match the symmetric mark-then-clear pattern used by runDueJob and executeJob. Fixes openclaw#91695
|
Codex review: needs real behavior proof before merge. Reviewed June 9, 2026, 9:30 AM ET / 13:30 UTC. Summary PR surface: Source +1. Total +1 across 1 file. Reproducibility: unclear. The review failed before ClawSweeper could establish a reproduction path. Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Risk before merge
Maintainer options:
Next step before merge
Review detailsBest possible solution: Retry the Codex review after fixing the execution failure. Do we have a high-confidence way to reproduce the issue? Unclear. The review failed before ClawSweeper could establish a reproduction path. Is this the best way to solve the issue? Unclear. Retry the review first so ClawSweeper can evaluate the actual issue and fix direction. AGENTS.md: unclear because the file could not be read completely. Codex review notes: model gpt-5.5, reasoning high; reviewed against 98d5c465308a. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +1. Total +1 across 1 file. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
Summary
markCronJobActive), so while a catch-up job is runningisCronJobActive(jobId)returnsfalse. The task-registry reconcile uses this marker to detect lost tasks — any catch-up run exceedingTASK_RECONCILE_GRACE_MS(5 min) is misclassified aslost, emitting a spuriousBackground task lostsystem message.runStartupCatchupCandidateinsrc/cron/service/timer.tscallstryCreateCronTaskRunand emitsaction:"started"but never callsmarkCronJobActive, unlike the sibling tick paths (runDueJobat line 888,executeJobat line 1672) which both mark active. The completion path still callsclearCronJobActiveviaapplyOutcomeToStoredJob, creating an asymmetric clear-without-mark.markCronJobActive(candidate.job.id)inrunStartupCatchupCandidatebeforetryCreateCronTaskRun, matching the pattern used byrunDueJob.src/cron/service/timer.ts— addedmarkCronJobActive(candidate.job.id)inrunStartupCatchupCandidateapplyOutcomeToStoredJob→clearCronJobActive) — it already works correctly for all pathsHEARTBEAT_SKIP_CRON_IN_PROGRESSguard — engaging it for catch-up is a separate concernReproduction
agentTurn)TASK_RECONCILE_GRACE_MS)lostand emitsBackground task lostwhile the job is still actively runningisCronJobActive(jobId)returnstrueduring the catch-up run, preventing falselostclassificationReal behavior proof
Behavior or issue addressed (91695): Startup catch-up cron runs now call
markCronJobActiveso the task registry reconcile correctly recognizes them as in-progress rather than classifying long-running catch-up jobs as lost.Real environment tested: Linux, Node 22 — Vitest with the cron vitest config against restart-catchup, timer, and jobs test suites
Exact steps or command run after this patch:
node scripts/run-vitest.mjs src/cron/service.restart-catchup.test.ts src/cron/service/timer.test.ts src/cron/service/timer.regression.test.ts src/cron/service.jobs.test.ts src/cron/active-jobs-manual-run.test.ts src/cron/service.failure-alert.test.tsEvidence after fix:
Observed result after fix: The
runStartupCatchupCandidatefunction now callsmarkCronJobActive(candidate.job.id)before dispatching the job, matching the symmetric mark-then-clear pattern already used byrunDueJobandexecuteJob. The restart-catchup test suite, timer regression tests, and active-jobs tests all continue to pass.What was not tested: A live gateway restart with a long-running catch-up cron job that exceeds the 5-minute reconcile grace period. The unit tests exercise the cron service state machine but not the full task-registry reconcile cycle with real time.
Repro confirmation: Before this patch,
runStartupCatchupCandidatehas nomarkCronJobActivecall betweentryCreateCronTaskRunandexecuteJobCoreWithTimeout, while the siblingrunDueJobpath (line 888) calls it. After this patch, both paths callmarkCronJobActivebefore dispatching.Risk / Mitigation
HEARTBEAT_SKIP_CRON_IN_PROGRESS) from engaging during startupMitigation: The heartbeat skip guard is a separate concern that was already not engaged for catch-up runs. This PR only fixes the reconcile false-positive; engaging the heartbeat guard for catch-up is a follow-up.
runStartupCatchupCandidatethrows aftermarkCronJobActivebut beforeclearCronJobActive, the marker could leakMitigation: The
executeJobCoreWithTimeoutcall is wrapped in try/catch, andapplyOutcomeToStoredJob(which callsclearCronJobActive) runs in the finally block via the outcome processing path.Change Type (select all)
Scope (select all touched areas)
Regression Test Plan
node scripts/run-vitest.mjs src/cron/service.restart-catchup.test.tsnode scripts/run-vitest.mjs src/cron/service/timer.test.tsnode scripts/run-vitest.mjs src/cron/service/timer.regression.test.tsnode scripts/run-vitest.mjs src/cron/service.jobs.test.tsReview Findings Addressed
N/A (initial submission)
Linked Issue/PR
Fixes #91695