Only unlink status.json on stop if this process still owns it#16
Only unlink status.json on stop if this process still owns it#16Devin-Holland wants to merge 2 commits into
Conversation
stop() unconditionally removed status.json. During an overlapping upgrade handoff (host-manager spawns the new symphony before stopping the old, both bound via SO_REUSEPORT) the incoming process has already rewritten status.json with its own pid, so the outgoing process would delete a healthy new process's status file — leaving the supervisor to see "not running" and spawn a redundant third instance. Guard the unlink on the status file still pointing at our own pid. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Companion PRs: symphony route-build resilience #15, host-manager cert fix HarperFast/host-manager#132. This one is a prerequisite for the upcoming host-manager overlapping-upgrade PR. |
There was a problem hiding this comment.
Code Review
This pull request updates the server shutdown sequence to only delete the status file if it is owned by the current process PID, preventing issues during overlapping upgrades. It also introduces integration tests to verify this behavior. The review feedback suggests tracking and cleaning up spawned child processes in the tests to prevent orphaned background processes in case of test failures or timeouts.
|
Consumer of this guard: host-manager overlapping-upgrade PR HarperFast/host-manager#133 (deploy #133 only alongside a symphony carrying this). |
Reap any still-running child in the after hook (SIGTERM then SIGKILL). Per PR review. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Superseded — this exact Thanks for catching the same issue independently — good instinct on the SO_REUSEPORT handoff hazard. (comment generated by an LLM — Claude Opus 4.8; posted on Kris's behalf) |
|
Superseded by #14 (merged to main, shipped in @harperfast/symphony@0.5.0). #14 bundled this exact 🤖 Generated with Claude Code (Opus 4.8) |
Summary
ServerState.stop()unconditionally removedstatus.json. During an overlapping upgrade handoff — host-manager spawns the new symphony before stopping the old one, both bound to the same ports viaSO_REUSEPORT— the incoming process has already rewrittenstatus.jsonwith its own pid. The outgoing process would then delete a healthy new process's status file, so the supervisor sees "not running" and spawns a redundant third instance.Guard the unlink on the status file still pointing at our own pid.
Why
Prerequisite for the host-manager overlapping (zero-downtime, fail-safe) symphony upgrade (separate host-manager PR). Without this guard the safe-upgrade handoff would strand the new process's status file.
Where to look
ts/server.tsstop()— readstatus.json, unlink only ifowner.pid === process.pid.readFileSyncthrows → caught → nothing to clean up (no stale file). A read→unlink race with the incoming process remains theoretically possible but is now a two-syscall window vs. the previous unconditional delete.__test__/server.spec.ts— covers both branches (own pid → removed; foreign pid → preserved).Notes for the reviewer
Companion (consumer): host-manager overlapping-upgrade PR — should land/deploy after this so the reorder is safe.
Generated by an LLM (Claude Opus 4.8).
🤖 Generated with Claude Code