forgejo-mcp-broker/internal/supervisor
Ole-Morten Duesund 03f67786be test(supervisor): stress tests for FD/goroutine/zombie leaks (forgejo-mcp-broker-31t)
Adds two stress tests:

  TestStress_NoLeaksAcross1000Cycles — spawns and reaps 1000 children
  in sequence, asserts FD count, goroutine count, and zombie status are
  all stable.

  TestStress_StopMidLifecycle — 200 cycles that exercise the Stop path
  (SIGTERM via Close+Signal) rather than relying on natural exit.

Bypassed by -short for the unit-test inner loop.

Notable findings:

* Using the helper-process pattern at this scale was a dead end. Each
  spawn re-execs the test binary, which inherits the parent's open FDs
  and runs Go's `testing` package init. Past a few hundred cycles the
  inner test binaries drag delivery of EOF on their inherited stderr
  pipe ends, leaving drainStderr goroutines blocked in bufio.ReadString
  even after Wait returned. Replacing the helper with /bin/true (for
  quick-exit) and /bin/cat (for echo-loop) sidesteps the recursion and
  is closer to the production case anyway: the broker spawns
  forgejo-mcp, not itself.

* Defensively close stdout/stderr handles in supervisor's reap goroutine
  after cmd.Wait returns. cmd.StderrPipe is supposed to be closed by
  Wait, but under load the kernel doesn't always deliver EOF promptly
  through Go 1.26's pidfd-based wait path; an explicit Close ensures
  drainStderr exits and FDs aren't held longer than needed.

Tests pass under -race with FD/goroutine deltas in single digits across
1000+200 cycles, and Wait4(-1) confirms no zombie children.

Closes forgejo-mcp-broker-31t. Phase 3 complete.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 16:04:34 +02:00
..
stress_test.go test(supervisor): stress tests for FD/goroutine/zombie leaks (forgejo-mcp-broker-31t) 2026-04-27 16:04:34 +02:00
supervisor.go test(supervisor): stress tests for FD/goroutine/zombie leaks (forgejo-mcp-broker-31t) 2026-04-27 16:04:34 +02:00
supervisor_test.go feat(supervisor): managed stdio subprocess (forgejo-mcp-broker-zuq) 2026-04-27 13:41:00 +02:00