Skip to content

Commit 055bf53

Browse files
oratisclaude
andcommitted
fix(ci): destroy stdout/stderr pipes after SIGKILL on timeout
Ubuntu CI symptom: even SIGKILL on the parent shell didn't unblock the `close` event — the test stayed pending past vitest's 5s ceiling. Root cause (most likely): dash on Ubuntu spawns `sleep` and when we kill dash, sleep gets reparented to init but its stdout/stderr fds were inherited from dash, keeping them alive from Node's POV. So Node's child.stdout/stderr never get EOF, and `close` event on the (already dead) dash never fires. Fix: explicitly destroy() both pipes after sending SIGKILL. That forces 'close' to fire immediately regardless of orphaned child state. Verified locally on macOS bash; pushing to test Ubuntu dash. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent dd2c750 commit 055bf53

2 files changed

Lines changed: 9 additions & 3 deletions

File tree

packages/core/src/hooks/dispatcher.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,11 @@ export function runCommand(
123123
let killed = false;
124124
const timer = setTimeout(() => {
125125
killed = true;
126-
// SIGKILL — see comment in bash.ts; dash on Ubuntu doesn't propagate SIGTERM.
126+
// SIGKILL + destroy pipes — see bash.ts; needed for orphaned grandchild
127+
// pipes on Ubuntu CI (dash doesn't propagate signals).
127128
child.kill('SIGKILL');
129+
child.stdout?.destroy();
130+
child.stderr?.destroy();
128131
}, opts.timeoutMs);
129132

130133
child.stdout.on('data', (c: Buffer) => {

packages/core/src/tools/bash.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,12 @@ export const BashTool: ToolHandler = {
6161
let killed = false;
6262
const timer = setTimeout(() => {
6363
killed = true;
64-
// SIGKILL (not SIGTERM) — on Ubuntu CI, dash doesn't propagate SIGTERM
65-
// to its children fast enough, leaving `sleep` orphaned past test timeout.
64+
// SIGKILL + destroy pipes — on Ubuntu CI, dash leaves orphaned children
65+
// whose inherited stdout/stderr fds keep `close` from firing on the
66+
// parent. Destroying the pipes forces close.
6667
child.kill('SIGKILL');
68+
child.stdout?.destroy();
69+
child.stderr?.destroy();
6770
}, timeoutMs);
6871

6972
child.stdout.on('data', (chunk: Buffer) => {

0 commit comments

Comments
 (0)