Skip to content

Only unlink status.json on stop if this process still owns it#16

Closed
Devin-Holland wants to merge 2 commits into
mainfrom
fix/status-ownership-guard
Closed

Only unlink status.json on stop if this process still owns it#16
Devin-Holland wants to merge 2 commits into
mainfrom
fix/status-ownership-guard

Conversation

@Devin-Holland

Copy link
Copy Markdown
Member

Summary

ServerState.stop() unconditionally removed status.json. During an overlapping upgrade handoff — host-manager spawns the new symphony before stopping the old one, both bound to the same ports via SO_REUSEPORT — the incoming process has already rewritten status.json with 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.ts stop() — read status.json, unlink only if owner.pid === process.pid.
  • Edge: if the first reconcile hit an invalid config, no status was ever written, the guard's readFileSync throws → 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

  • Cross-model review (Codex/Gemini) could not run in this environment — reviewed with a same-model Harper-domain deep-review pass only.

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

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>
@Devin-Holland

Copy link
Copy Markdown
Member Author

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.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread __test__/server.spec.ts
Comment thread __test__/server.spec.ts
@Devin-Holland

Copy link
Copy Markdown
Member Author

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>
@kriszyp

kriszyp commented Jul 6, 2026

Copy link
Copy Markdown
Member

Superseded — this exact stop() ownership guard shipped in #14 (commit 146750c) and is released in @harperfast/symphony@0.5.0. #14 merged first as part of the broader cert-rotation resilience work (per-route isolation + cert-file hot reload + this guard), so this PR is now redundant and can be closed. host-manager#133 can depend on ^0.5.0 directly instead of this PR.

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)

@kriszyp

kriszyp commented Jul 6, 2026

Copy link
Copy Markdown
Member

Superseded by #14 (merged to main, shipped in @harperfast/symphony@0.5.0). #14 bundled this exact status.json ownership guard as its Fix 3 — stop() now only unlinks when current.pid === process.pid (ts/server.ts:384), same SO_REUSEPORT upgrade-handoff rationale, same host-manager #133 gating, plus the ownership-guard test in server.spec.ts. Closing as redundant.

🤖 Generated with Claude Code (Opus 4.8)

@kriszyp kriszyp closed this Jul 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants