fix(update): restart managed gateway when update handoff fails after stop#92111
Conversation
|
Codex review: needs maintainer review before merge. Reviewed June 15, 2026, 12:24 PM ET / 16:24 UTC. Summary PR surface: Source +93, Tests +160. Total +253 across 2 files. Reproducibility: yes. Current main clearly exits failed detached handoffs without service recovery, and the PR body supplies live before/after systemd output showing the outage and recovery; I did not rerun the live scenario in this read-only review. Review metrics: none identified. Stored data model 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
Security Review detailsBest possible solution: Land the detached-helper recovery after normal checks if maintainers accept the platform-proof gap; otherwise request native launchd and Windows failed-handoff proof without moving the fix out of the helper owner. Do we have a high-confidence way to reproduce the issue? Yes. Current main clearly exits failed detached handoffs without service recovery, and the PR body supplies live before/after systemd output showing the outage and recovery; I did not rerun the live scenario in this read-only review. Is this the best way to solve the issue? Yes. The detached helper is the best fix location because it is the process that survives after the gateway is stopped; the CLI restart path is not sufficient for child update failures that bypass the normal restore path. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 865e4db1cd0a. Label changesLabel justifications:
Evidence reviewedPR surface: Source +93, Tests +160. Total +253 across 2 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 |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
@clawsweeper re-review |
47cddd9 to
36ec65d
Compare
36ec65d to
bd21e48
Compare
|
Maintainer verification complete on exact head
The PR remains three commits, preserving the contributor’s two commits plus the maintainer launchd correction. |
Summary
Fixes #92088. When a managed-service update handoff fails after the update command has already stopped
openclaw-gateway.service, nothing restarted the gateway, leaving the host with no live gateway until manual recovery (loaded inactive dead, reported on Ubuntu systemd user services).The detached handoff helper is the only process that survives the update command, so it now performs a best-effort gateway service start whenever the managed update command fails to spawn, exits nonzero, or dies on a signal (covers OOM kills and
exit 127style wrapper failures that bypass the CLI's own restore path):systemctl --user start <unit>(a no-op when the unit is already active, so failures that happen before the stop, or after the CLI already restored the gateway, do not bounce a healthy gateway)launchctl kickstart, falling back toenableplusbootstrapwith the agent plist (the CLI stop path usesbootout)schtasks /Runon the gateway taskThe service identity (unit/label/task name) is resolved at handoff start from the same env vars and
daemon/constants.jsresolvers the rest of the daemon code uses, and passed to the helper via its params file as aserviceRecoverydescriptor.Also closes the one CLI failure path that exited without restoring a gateway it had stopped: the plugin post-update sync error branch in
src/cli/update-cli/update-command.tsnow callsmaybeRestartServiceAfterFailedMutableUpdatelike the sibling error/skipped branches.The issue's stale
update-restart-pendingsentinel note is already handled on main: the helper marks the pending sentinel aserrorviamarkUpdateSentinelFailureIfPendingon the same failure paths.Real behavior proof
Behavior addressed: a failed managed update handoff left
openclaw-gateway.servicestopped (loaded inactive dead, gateway HTTP unreachable) with no automatic recovery.Real environment tested: Ubuntu Linux (kernel 6.8), systemd user manager, real
openclaw-gateway.serviceinstalled byopenclaw gateway installfrom this checkout's dist build, gateway serving HTTP 200 on port 18789. The real generatedhandoff.cjsran inside a realsystemd-run --user --scopetransient unit viastartManagedServiceUpdateHandoff, with the managed update command replaced by a stub that reproduces the reported timeline: stopopenclaw-gateway.service, then exit 127.Exact steps or command run after this patch:
systemctl --user start openclaw-gateway.service, confirmactiveand HTTP 200, then run a driver that callsstartManagedServiceUpdateHandoff({ supervisor: "systemd", env: { ...process.env, OPENCLAW_SYSTEMD_UNIT: "openclaw-gateway.service" }, ... })against the patched module with the failing update stub, wait for the handoff to finish, then checksystemctl --user is-active openclaw-gateway.service, the unit list, HTTP on 18789, and the handoff log.Evidence after fix:
Same scenario on unpatched main (418d7e1) for contrast:
No-bounce check on the patched build: an update command that fails with exit 1 before stopping the gateway leaves the running gateway untouched,
MainPID before=46787 after=46787 unit=active, and the helper logsgateway service recovery succeededfrom the idempotentsystemctl --user start.Observed result after fix: the gateway service is automatically started again within about 20 ms of the failed update command exiting; the host keeps a live gateway instead of a full outage, and successful updates and pre-stop failures see no extra restart.
What was not tested: launchd and schtasks recovery commands were not executed against real macOS/Windows service managers (covered by unit tests asserting the descriptor and the command wiring; the command sequences mirror
src/cli/update-cli/restart-helper.ts); the plugin post-update sync error branch inupdate-command.tshas no existing test harness and was verified by code reading against the sibling error/skipped branches.Maintainer follow-up
Autoreview found one launchd edge case after the contributor proof:
bootstrapcan report an already-loaded/in-progress label while the service still needs a start. The final commit retries start-onlykickstartafter that failure, preserving the no-bounce policy and adding a regression test for the fullkickstart→enable→ failedbootstrap→kickstartsequence.Verification
node scripts/run-vitest.mjs src/infra/update-managed-service-handoff.test.tspasses (9 tests); the contributor's 3 core regression tests fail on unpatched main and pass with this changepnpm tsgo:coreandpnpm tsgo:core:testcleannode scripts/run-oxlint.mjsandoxfmt --checkclean on the touched filespnpm check:changedpasses in Testboxtbx_01kv78qyb9v89ffrtesqekjdgb(run)systemctl --user start, and returns active with HTTP 200 (run)Reported by @ofan.