perf(startup): scope orphan reapers to server commands, share one process scan, add opt-out - #411
Merged
Merged
Conversation
…cess scan, add opt-out The two orphan reapers ran before argv parsing (even --version paid the double scan), blocked startup, and walked /proc / ran ps independently over identical data (issue #399). Now: - src/utils/process-scan.ts produces (pid, args) rows once — one bounded /proc walk on linux, one ps -ww -A on darwin; win32 stays one filtered CIM query per process name (unfiltered would cost more). The reapers' platform listers are thin wrappers applying their marker matchers. - src/utils/startup-janitor.ts orchestrates: one scan feeds both reapers via their existing lister seams; kicked fire-and-forget from the stdio/sse/http command actions only, so the transport comes up immediately and non-server invocations never scan. Safe concurrently: reapers only kill processes whose recorded owner pid is dead. - MCP_SKIP_ORPHAN_REAPERS=1 opt-out for PID-namespaced containers. - The janitor also sweeps stale session run dirs (proxy-*.log / dap-trace-*.ndjson older than 7 days) under the tmpdir session log base — the follow-through deferred from #403. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
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.
Fixes #399
The two startup orphan reapers were awaited at the top of
main(), before commander even parsed argv — so--version,--help, and bad-arg errors all paid the double process scan, startup blocked on it, and the two reapers walked/proc(or ranps) independently and concurrently over identical data.Changes
One shared scan — new
src/utils/process-scan.tsproduces(pid, args)rows once: one bounded/procwalk on Linux, oneps -ww -Aon Darwin. Windows deliberately stays one name-filtered CIM query per process name (java.exe/node.exe) — a single unfilteredWin32_Processquery would be strictly more expensive than the two filtered ones. Each reaper's platform listers are now thin wrappers applying its marker matcher over the scan rows (~170 lines of duplicated platform code deleted); the existing*-internalstests pass unchanged through the wrappers.Scoped to server commands, fire-and-forget — new
src/utils/startup-janitor.tsorchestrates: one scan feeds both reapers via their existinglisterseams. It's kicked (not awaited) from the stdio/sse/http command actions only, so:--version/--help/check-rust-binarynever pay the scan;tests/unit/index.test.tsno longer accidentally executes real PowerShell CIM queries three times per run (it previously called realmain()with unmocked reapers).Opt-out —
MCP_SKIP_ORPHAN_REAPERS=1skips the process scans entirely (PID-namespaced containers where orphans are impossible). Documented in the setup guide's env table.Stale session-run sweep (deferred here from #403) — the janitor also removes
run-<ts>dirs older than 7 days under the session log base (os.tmpdir()/debug-mcp-server/sessions/…, holdingproxy-<id>.log/dap-trace-<id>.ndjson), then prunes emptied session dirs. mtime-based, best-effort: a live session's run dir stays fresh because the proxy logger writes into it.Not in scope (as the issue flagged): the sync
openSync/readSyncsingle-buffer scan rewrite — it would rewrite the fs mock preambles in both internals test suites for a further ~25 ms/12 MB; the shared-scan + off-startup-path change removes the pain first.Tests (TDD, watched fail first)
process-scan.test.ts: linux NUL-split + numeric-only + bounded reads, darwin ps parsing, win32 per-name queries with one-failure tolerance.startup-janitor.test.ts: single scan feeds both reapers' listers with correctly matched rows; env opt-out skips everything; reaper rejection logged, never thrown; sweep removes stale run dirs (real temp dirs +utimes), keeps fresh ones, prunes emptied session dirs.index.test.ts: janitor NOT invoked bymain()setup alone (i.e. never for--version); invoked exactly once when the stdio action runs.npm testgreen,npm run lintclean.🤖 Generated with Claude Code