fix(core): track PIDs independently to survive removeProcess() race during shutdown

The direct child process may die from terminal SIGINT before ProcessLifecycle
runs shutdown, causing removeProcess() to clear it. Now killAll() uses a
persistent trackedPids Set that is never cleared by removeProcess(), ensuring
grandchild process trees are always killed.
This commit is contained in:
2026-03-03 23:56:52 +00:00
parent da24218bef
commit 34b9aa4463
2 changed files with 28 additions and 25 deletions

View File

@@ -187,22 +187,18 @@ export class ProcessLifecycle {
});
}
/** Synchronous last-resort: SIGKILL any remaining child processes. */
/** Synchronous last-resort: SIGKILL any remaining tracked PIDs. */
private handleExit(): void {
const instances = ProcessLifecycle.getInstances();
let killed = 0;
for (const instance of instances) {
const processes = instance.processesToEnd.getArray();
for (const child of processes) {
const pid = child.pid;
if (pid && !child.killed) {
try {
process.kill(pid, 'SIGKILL');
killed++;
} catch {
// Process may already be dead
}
for (const pid of instance.trackedPids) {
try {
process.kill(pid, 'SIGKILL');
killed++;
} catch {
// Process already dead
}
}
}