fix: kill process group on timeout and handle stdin EPIPE
- Use detached process group (non-Windows) + process.kill(-pid) to kill the entire process tree, not just the outer shell wrapper - Add proc.stdin error listener to absorb EPIPE when child exits before stdin write completes
This commit is contained in:
parent
91530234ec
commit
a31109bb07
@ -52,9 +52,11 @@ export async function executeHookCommand(
|
|||||||
let settled = false;
|
let settled = false;
|
||||||
let killTimer: ReturnType<typeof setTimeout> | null = null;
|
let killTimer: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
|
||||||
|
const isWin32 = process.platform === "win32";
|
||||||
const proc = spawn(finalCommand, {
|
const proc = spawn(finalCommand, {
|
||||||
cwd,
|
cwd,
|
||||||
shell: true,
|
shell: true,
|
||||||
|
detached: !isWin32,
|
||||||
env: { ...process.env, HOME: home, CLAUDE_PROJECT_DIR: cwd },
|
env: { ...process.env, HOME: home, CLAUDE_PROJECT_DIR: cwd },
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -69,6 +71,7 @@ export async function executeHookCommand(
|
|||||||
stderr += data.toString();
|
stderr += data.toString();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
proc.stdin?.on("error", () => {});
|
||||||
proc.stdin?.write(stdin);
|
proc.stdin?.write(stdin);
|
||||||
proc.stdin?.end();
|
proc.stdin?.end();
|
||||||
|
|
||||||
@ -92,17 +95,23 @@ export async function executeHookCommand(
|
|||||||
settle({ exitCode: 1, stderr: err.message });
|
settle({ exitCode: 1, stderr: err.message });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const killProcessGroup = (signal: NodeJS.Signals) => {
|
||||||
|
try {
|
||||||
|
if (!isWin32 && proc.pid) {
|
||||||
|
process.kill(-proc.pid, signal);
|
||||||
|
} else {
|
||||||
|
proc.kill(signal);
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
};
|
||||||
|
|
||||||
const timeoutTimer = setTimeout(() => {
|
const timeoutTimer = setTimeout(() => {
|
||||||
if (settled) return;
|
if (settled) return;
|
||||||
// Try graceful shutdown first
|
// Kill entire process group to avoid orphaned children
|
||||||
try {
|
killProcessGroup("SIGTERM");
|
||||||
proc.kill("SIGTERM");
|
|
||||||
} catch {}
|
|
||||||
killTimer = setTimeout(() => {
|
killTimer = setTimeout(() => {
|
||||||
if (settled) return;
|
if (settled) return;
|
||||||
try {
|
killProcessGroup("SIGKILL");
|
||||||
proc.kill("SIGKILL");
|
|
||||||
} catch {}
|
|
||||||
}, SIGKILL_GRACE_MS);
|
}, SIGKILL_GRACE_MS);
|
||||||
// Append timeout notice to stderr
|
// Append timeout notice to stderr
|
||||||
stderr += `\nHook command timed out after ${timeoutMs}ms`;
|
stderr += `\nHook command timed out after ${timeoutMs}ms`;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user