fix(mcp): reap serve --mcp child when parent is SIGKILL'd (#286)
Add a PPID watchdog to the MCP server so a `codegraph serve --mcp` child terminates when its host (Claude Code, opencode, …) is force-killed — OOM killer, `kill -9`, container teardown — and the stdin close handlers don't fire. The child would otherwise linger indefinitely, holding inotify watches, file descriptors, and the SQLite WAL. Also propagates the host PID across the `--liftoff-only` re-exec (CODEGRAPH_HOST_PPID) so the watchdog reaps the orphan on the from-source path too, not just the bundled launcher. Poll interval is CODEGRAPH_PPID_POLL_MS (default 5000ms, 0 disables). Resolves #277. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
fd6a649518
commit
fb45959af7
@@ -46,6 +46,19 @@ export const WASM_RUNTIME_FLAGS: readonly string[] = ['--liftoff-only'];
|
||||
*/
|
||||
const RELAUNCH_GUARD_ENV = 'CODEGRAPH_WASM_RELAUNCHED';
|
||||
|
||||
/**
|
||||
* Env var carrying the *host* PID (the relauncher's own parent) across the
|
||||
* re-exec. Without `--liftoff-only` the CLI re-execs itself once, inserting an
|
||||
* intermediate process between the MCP host and the server. That intermediate
|
||||
* stays alive (blocked in spawnSync) even after the host is killed, so the
|
||||
* server's PPID watchdog can't detect the host's death by watching its own
|
||||
* `process.ppid`. Passing the host PID through lets the watchdog poll it
|
||||
* directly. Unset on the no-re-exec path (bundled launcher / flag already
|
||||
* present), where the server is already a direct child of the host. See
|
||||
* src/mcp/index.ts (#277).
|
||||
*/
|
||||
export const HOST_PPID_ENV = 'CODEGRAPH_HOST_PPID';
|
||||
|
||||
/** True when every required WASM runtime flag is already present in `execArgv`. */
|
||||
export function processHasWasmRuntimeFlags(
|
||||
execArgv: readonly string[] = process.execArgv
|
||||
@@ -84,7 +97,7 @@ export function relaunchWithWasmRuntimeFlagsIfNeeded(scriptPath: string): void {
|
||||
const argv = buildRelaunchArgv(scriptPath, process.argv.slice(2));
|
||||
const result = spawnSync(process.execPath, argv, {
|
||||
stdio: 'inherit',
|
||||
env: { ...process.env, [RELAUNCH_GUARD_ENV]: '1' },
|
||||
env: { ...process.env, [RELAUNCH_GUARD_ENV]: '1', [HOST_PPID_ENV]: String(process.ppid) },
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
|
||||
Reference in New Issue
Block a user