On Windows the PPID watchdog could never fire: orphans aren't reparented, so `process.ppid` stays constant after the parent dies (defeating the ppid-change check), and the standalone bundle pre-bakes `--liftoff-only`, skipping the relaunch that sets `CODEGRAPH_HOST_PPID` (defeating the host-liveness check). With neither signal available, an orphaned proxy / direct server ran forever, the shared daemon never saw the client disconnect, and its idle timer never armed — node processes accumulated until CPU saturated. Add a win32-only signal: poll the original parent's liveness directly, since ppid is stable there. Gated to Windows so POSIX double-fork cases keep relying on the ppid-change signal (a dead original parent is not proof of orphaning on POSIX). The decision is extracted into a pure, unit-tested helper shared by all three watchdog sites (proxy socket, proxy local-handshake, direct mode). Validated on a real Windows 11 VM: in the exact bundle scenario (direct mode, no HOST_PPID) an orphaned server now exits within one watchdog poll via the new path; the POSIX reparent path is unchanged and its integration test still passes. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
4e5cf2de56
commit
565eb20e26
+8
-7
@@ -49,6 +49,7 @@ import {
|
||||
} from './daemon';
|
||||
import { connectWithHello, runLocalHandshakeProxy } from './proxy';
|
||||
import { getDaemonSocketPath } from './daemon-paths';
|
||||
import { supervisionLostReason } from './ppid-watchdog';
|
||||
import { HOST_PPID_ENV } from '../extraction/wasm-runtime-flags';
|
||||
|
||||
/**
|
||||
@@ -423,13 +424,13 @@ export class MCPServer {
|
||||
const pollMs = parsePpidPollMs(process.env.CODEGRAPH_PPID_POLL_MS);
|
||||
if (pollMs <= 0) return;
|
||||
this.ppidWatchdog = setInterval(() => {
|
||||
const current = process.ppid;
|
||||
const ppidChanged = current !== this.originalPpid;
|
||||
const hostGone = this.hostPpid !== null && !isProcessAlive(this.hostPpid);
|
||||
if (ppidChanged || hostGone) {
|
||||
const reason = ppidChanged
|
||||
? `ppid ${this.originalPpid} -> ${current}`
|
||||
: `host pid ${this.hostPpid} exited`;
|
||||
const reason = supervisionLostReason({
|
||||
originalPpid: this.originalPpid,
|
||||
currentPpid: process.ppid,
|
||||
hostPpid: this.hostPpid,
|
||||
isAlive: isProcessAlive,
|
||||
});
|
||||
if (reason) {
|
||||
process.stderr.write(
|
||||
`[CodeGraph MCP] Parent process exited (${reason}); shutting down.\n`
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user