fix(cron): avoid gateway restart on setup timeout#96396
Conversation
|
Codex review: needs maintainer review before merge. Reviewed June 24, 2026, 8:36 AM ET / 12:36 UTC. Summary PR surface: Source -11, Tests -5. Total -16 across 8 files. Reproducibility: yes. for the source-level path: current main and v2026.6.10 call requestSafeGatewayRestart and set restartRecoveryPending when an isolated setup timeout is notified. The PR body adds terminal runtime proof for the after-fix no-restart/backoff path, but I did not reproduce the full systemd saturation incident. Review metrics: 1 noteworthy metric.
Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land the job-local backoff default only with maintainer-approved escalation semantics for corruption-class setup failures, while keeping the focused no-restart and scheduler rearm regression coverage. Do we have a high-confidence way to reproduce the issue? Yes for the source-level path: current main and v2026.6.10 call requestSafeGatewayRestart and set restartRecoveryPending when an isolated setup timeout is notified. The PR body adds terminal runtime proof for the after-fix no-restart/backoff path, but I did not reproduce the full systemd saturation incident. Is this the best way to solve the issue? Mostly yes for the narrow no-restart default: the patch removes the direct process-restart side effect at the cron/Gateway boundary and keeps existing job error backoff. The remaining question is product policy for when, if ever, setup timeouts should escalate to Gateway restart. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against e4763b0631bf. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source -11, Tests -5. Total -16 across 8 files. 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
|
|
@clawsweeper re-review Added the requested live runtime proof to the PR body under "Additional Live Runtime Proof After ClawSweeper Review". The proof uses a real Node process, actual CronService runtime code, and the real 60s setup watchdog; observed |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
Merged via squash.
|
* fix(cron): avoid gateway restart on setup timeout * fix(cron): avoid gateway restart on setup timeout --------- Co-authored-by: Radek Sienkiewicz <[email protected]>
* fix(cron): avoid gateway restart on setup timeout * fix(cron): avoid gateway restart on setup timeout --------- Co-authored-by: Radek Sienkiewicz <[email protected]>
* fix(cron): avoid gateway restart on setup timeout * fix(cron): avoid gateway restart on setup timeout --------- Co-authored-by: Radek Sienkiewicz <[email protected]> (cherry picked from commit 19707cc)
* fix(cron): avoid gateway restart on setup timeout * fix(cron): avoid gateway restart on setup timeout --------- Co-authored-by: Radek Sienkiewicz <[email protected]> (cherry picked from commit 19707cc)
Fixes #95784
What Problem This Solves
An isolated cron setup timeout currently escalates a tick-level failure into a full Gateway restart. Current
main,v2026.6.9, and latest stablev2026.6.10all still haveonIsolatedAgentSetupTimeoutcallingrequestSafeGatewayRestart({ delayMs: 0 })fromsrc/gateway/server-cron.ts, andmaybeNotifyIsolatedAgentSetupTimeoutmarksstate.restartRecoveryPending = trueinsrc/cron/service/timer.ts.Under event-loop saturation, that restart does not fix the saturated workload. It can instead kill unrelated in-flight embedded runs and freeze cron scheduling behind restart recovery.
Why This Change Was Made
This changes the setup-timeout response to stay at the cron-job boundary:
src/gateway/server-cron.tslogs the isolated setup timeout but no longer requests a Gateway restart.src/cron/service/timer.tsno longer flipsrestartRecoveryPendingwhen the setup-timeout notification fires.This is intentionally narrower than adaptive setup timeouts or a new corruption detector. It removes the destructive unconditional restart path while preserving the existing timeout detection, cleanup, error recording, and backoff behavior.
User Impact
When one isolated cron job times out during setup, OpenClaw now backs off that job without restarting the Gateway. In-flight non-cron embedded work is preserved, and cron scheduling is not frozen behind restart recovery just because the timeout notification was sent.
Evidence
Current/shipped behavior checked:
Verification run in the dedicated
openclaw-95784worktree:Observed results:
src/cron/active-jobs-manual-run.test.ts: 1 file passed, 6 tests passed.src/gateway/server-cron.test.ts: 2 files passed, 48 tests passed.src/cron/service/timer.regression.test.ts: 1 file passed, 64 tests passed.oxfmt --check: all 8 matched files use the correct format.oxlint: passed with no diagnostics.git diff --check: passed.What was not tested: a full live
systemd --userGateway under production event-loop saturation. The changed behavior is source-level deterministic: the unconditional restart call and restart-recovery state flip are removed, and the focused tests cover the Gateway handler, manual timeout notification, scheduler re-arm, and scheduled-batch continuation paths.Additional Live Runtime Proof After ClawSweeper Review
ClawSweeper requested real behavior proof beyond focused tests. I added a local live runtime proof using a real Node process, the actual
CronServiceruntime, and the real 60-second setup watchdog. This is not a Vitest run and does not use fake timers.Command shape:
The proof script creates a temporary cron service state, registers a
SIGUSR1listener, runs an isolated agent cron job whose runner intentionally never reachesonExecutionStarted, waits for the real setup watchdog to fire, then reads back the job runtime state.Observed output, with only the temp directory elided:
{ "proof": "issue-95784 live CronService setup-timeout no-restart proof", "pid": 57726, "elapsedMs": 60161, "runResult": { "ok": true, "ran": true }, "setupTimeoutNotification": { "jobId": "bda19f66-56aa-418e-82a3-5a32b8ec7025", "error": "cron: isolated agent setup timed out before runner start", "timeoutMs": 60000, "atMs": 60160 }, "sigusr1Count": 0, "handoffExists": false, "jobState": { "lastRunStatus": "error", "lastStatus": "error", "lastDurationMs": 60026, "lastError": "cron: isolated agent setup timed out before runner start", "lastErrorReason": "timeout", "consecutiveErrors": 1, "consecutiveSkipped": 0 }, "warningMessages": [ "cron: job run returned error status", "cron: isolated agent setup timed out before runner start; backing off job without gateway restart" ] }Proof result: after the real setup watchdog fired, the cron job was recorded as an error with backoff state (
consecutiveErrors: 1), noSIGUSR1restart was emitted (sigusr1Count: 0), no supervisor restart handoff was written (handoffExists: false), and the process stayed alive long enough to read back the job state.