fix(server): kill spawned odek serve when bodek dies - #117
Merged
Conversation
bodek's Stop() path shuts the spawned server down gracefully, but a SIGKILLed or crashed bodek left the child orphaned — macOS has no PDEATHSIG. Spawn odek serve in its own process group and launch a self-terminating re-exec guard (bodek __bodek-watchdog <parent> <server>) that SIGINTs the server's group when the parent dies, escalating to SIGKILL after a grace period. Zombie-aware liveness probes (kinfo on darwin, /proc on linux). Graceful Stop retires the guard first; the guard is best-effort and a no-op on windows.
Three findings from the OS-expert review round: - PID-reuse kill: the guard now captures the target's start-time token (kern.proc kinfo on darwin, /proc stat field 22 on linux) and never signals a recycled PID — liveness AND identity must both hold. - False self-termination: Run now exits when the server dies while the parent lives, instead of lingering the whole session (the lingering guard widened the PID-reuse window it was guarding against). - Leader-only escalation: Stop now signals the server's whole process group (not just the leader) for both SIGINT and the SIGKILL fallback, so the server's own subprocesses follow it down.
Round-2 adversarial findings: when liveness observation degrades (EPERM from kill -0 on foreign processes, unreadable /proc under hidepid, kinfo failure on darwin), the watchdog previously concluded 'dead' — a false-dead kills a healthy server or an innocent recycled PID. All degraded paths now fail safe (alive): at worst the guard never fires, never over-kills. The bare-pid signal fallback keeps its original reach but is documented as identity-guarded: every caller verifies pid identity (start-time token or live Process handle) immediately before signalling.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
bodek | f2319b6 | Commit Preview URL Branch Preview URL |
Sep 12 2026, 04:53 PM |
The windows signalServer stub referenced syscall and os without importing them; darwin CI never cross-compiled, so it only broke the Windows Build & Vet leg. Verified with GOOS=windows go build && go vet.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A
kill -9ed or crashed bodek left its spawnedodek servechild orphaned —Stop()only covers graceful exits, and macOS has noPDEATHSIG. Users kept finding strayodek serveprocesses after crashes.Fix
odek servenow spawns withSetpgid, isolated from bodek's group.bodek __bodek-watchdog <parentPID> <serverPID>— a self-terminating guard process that polls the parent (500ms) and, when it dies for any reason, SIGINTs the server's process group (graceful), escalating to SIGKILL after 8s.Stop()retires the guard first (kill + async reap) before its own SIGINT/group-SIGKILL shutdown.Hardening (3 rounds of adversarial OS-expert review)
P_starttimeon darwin,/proc/<pid>/statfield 22 on linux) and re-verifies identity before every signal — a recycled PID is never signalled.hidepid, kinfo failure) reads as alive — at worst the guard never fires; a false-dead could kill a healthy server.Windows: no-op (no process-group signalling); spawn/Stop behavior unchanged.
Verification
internal/watchdog,internal/server,cmd/bodek(including re-exec dispatch through the real test binary)test -race