You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: destroy piped streams on child exit to prevent grandchild deadlock (tinylibs#137)
* test: verify exec completes when grandchild holds piped stdout
When a child process spawns a grandchild that inherits the piped stdout
fd (fd 1), the grandchild keeps the pipe open after the child exits.
Without the fix, both `await exec()` and the async iterator hang
indefinitely because the piped streams never end.
Each test runs in a subprocess (spawnSync with a 10s timeout) so the
orphaned grandchild doesn't block vitest. A 5s inner race detects
whether exec completes or hangs.
* fix: destroy piped streams on child exit to prevent grandchild deadlock
When a child process spawns a grandchild that inherits the piped
stdout/stderr file descriptors, the grandchild holds them open after the
child exits. Node's close event waits for all fds to be released, so
it never fires. readStream and combineStreams hang indefinitely because
the streams never end.
Listen for the exit event (fires when the process exits, regardless of
pipe state) and destroy the piped streams. This forces the PassThrough
and readline consumers to complete.
Refs: lint-staged/lint-staged#1800
* test: add grandchild fixture scripts for pipe inheritance tests
Static test fixtures that spawn a long-lived grandchild process
inheriting the piped stdout fd, simulating tsserver inheriting
eslint's piped streams through lint-staged/tinyexec.
* test: restructure grandchild tests to use static fixtures
Use committed fixture scripts instead of generated inline scripts.
Run tests in a subprocess with isolated stdio so orphaned
grandchildren don't block vitest's teardown. Clean up grandchildren
via pkill with a marker comment in the fixture scripts.
* fix: use setImmediate instead of setTimeout for stream cleanup
setImmediate is sufficient to let buffered data drain before destroying
the streams. Removes the timer tracking in _resetState and _onClose
that was needed for the setTimeout approach.
* chore: clarify comment
* test: move tests into main
* fix: account for piped streams
---------
Co-authored-by: James Garbutt <43081j@users.noreply.github.com>
0 commit comments