Tags: jpillora/overseer
Tags
fix: bound cmd.Wait via WaitDelay so master can't hang on inherited fds A worker subprocess that inherits the worker's fd 2 (the pipe write-end when cmd.Stderr is a non-*os.File like our MultiWriter for panic detection) and outlives the worker keeps the pipe open after the worker exits. cmd.Wait then blocks forever in its internal I/O drain loop, the fork() select never fires on cmdwait, and the master never spawns the next worker — a real 10-minute outage observed on rais-main where a vscode-server grandchild had inherited the pipe. The new Config.WaitDelay (default = TerminateTimeout) is wired straight into cmd.WaitDelay. After the worker exits, Go's exec force-closes parentIOPipes once WaitDelay elapses, the I/O goroutine sees EOF, and cmd.Wait returns so the master can proceed. Also harden the exit-code extraction: prefer cmd.ProcessState (always set after process exit) and use errors.As so a WaitDelay-wrapped exit error still reports the true code instead of falling back to 1. Integration test reproduces the bug with a real binary that spawns a long-running grandchild via cmd.Stderr = os.Stderr and verifies cmd.Wait hangs without WaitDelay and returns within budget with it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fix signal dropped during fork window; queue and drain on Start A signal arriving between `mp.workerCmd = cmd` and `cmd.Start()` returning was silently dropped (Process still nil), so a SIGTERM racing a fresh fork never reached the new worker and systemd had to wait out TerminateTimeout before sending SIGKILL. handleSignal now queues under a new workerMux; fork drains the queue once Start succeeds. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fix OnPanic skipped on worker panic; preempt-SIGURG races cmdwait Filter SIGURG (Go 1.14+ runtime preemption) in handleSignal and stop exiting from sendSignal when the worker is already gone, so panicking workers reach the cmdwait branch where OnPanic fires and the real exit code propagates. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
add OnPanic + ShouldRestart hooks, new opanic subpackage OnPanic: when set, slave stderr is tailed through a fixed-size ring buffer and scanned by panicparse on exit; matching snapshots are delivered to the user callback in a goroutine so a slow consumer can't stall the fork loop. ShouldRestart: gates auto-restarts after a fetch. When it returns false the restart is recorded as pending and re-evaluated on each fetch-loop iteration. Manual Restart()/RestartSignal bypass the gate. Restart orchestration now claims restarting/pendingRestart under restartMux so the fetch loop, signal handler and fork goroutine don't race on shared state. Panic detection lives in its own opanic subpackage and re-exports the panicparse snapshot types so consumers only import opanic. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PreviousNext