Skip to content

fix(mcp): reap dropped daemon children without leaking pending exit statuses - #1371

Open
ohdearquant wants to merge 3 commits into
mainfrom
fix/daemon-recovery-followups
Open

fix(mcp): reap dropped daemon children without leaking pending exit statuses#1371
ohdearquant wants to merge 3 commits into
mainfrom
fix/daemon-recovery-followups

Conversation

@ohdearquant

Copy link
Copy Markdown
Owner

Closes #1271.

Two defects in the daemon replacement path:

  1. Zombie exit statuses left pending. forward_or_spawn drops the Child handle for a killed incumbent without calling wait(). process_is_alive now reaps via waitpid(WNOHANG) on its probe path, and also on the ps-stat zombie branch: previously a child that exited between the WNOHANG probe and the ps read was reported dead without being reaped, leaving its exit status pending for the life of the process. Non-children fail with ECHILD and are left for their own parent.

  2. Replacement-race test fixture deadlock. The peer-replacement test held KHIVE_LOCK across an await on the incumbent exit gate while run_daemon blocked acquiring the same lock, wedging the serial test convoy (suite hung ~20 min). The fixture now binds the replacement probe socket directly and serves acks from the already-bound listener.

Verification: cargo test -p khive-mcp 259+90 green in 46s (previously deadlocked); the reap regression test passes 8/8 consecutive runs (previously 1/5); clippy -D warnings and fmt clean.

Leo and others added 3 commits July 23, 2026 13:30
… spawn

Positively reap owned exited daemon children via waitpid(WNOHANG) in the
exit-wait path, keeping the ps-based zombie check for non-owned PIDs, and
re-probe daemon identity after a successful kill while holding the boot
lock so a healthy replacement spawned by a concurrent peer is never
double-spawned. Regression tests cover both behaviors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…est fixture

process_is_alive could report a child dead via the ps zombie check without
reaping it: when the child exited between the waitpid(WNOHANG) probe and the
ps stat read, the exit status stayed pending for the life of the process.
Reap on the zombie branch before returning; non-children fail with ECHILD and
are left for their own parent.

The kill_and_respawn_skips_spawn_when_peer_replaces_daemon_during_incumbent_wait
fixture held KHIVE_LOCK across an await on the incumbent exit gate while
run_daemon blocked acquiring the same lock, deadlocking the serial test convoy.
Bind the replacement probe socket directly and serve acks from the already-bound
listener instead of driving a full run_daemon.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…stant

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ohdearquant
ohdearquant marked this pull request as ready for review July 24, 2026 02:24
@ohdearquant
ohdearquant enabled auto-merge (squash) July 24, 2026 02:26
@ohdearquant
ohdearquant disabled auto-merge July 24, 2026 12:22
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.

daemon: stale-daemon recovery spawns a replacement without confirming the incumbent exited, yielding two daemons on one socket path

1 participant