Skip to content

child_process: emit close after parent disconnect - #66069

Closed
rasadregmi wants to merge 1 commit into
nodejs:mainfrom
rasadregmi:fix/child-process-close
Closed

rasadregmi wants to merge 1 commit into
nodejs:mainfrom
rasadregmi:fix/child-process-close

Conversation

@rasadregmi

Copy link
Copy Markdown

When the parent calls subprocess.disconnect() before the IPC channel reaches EOF, the close event is never emitted after the child exits. disconnect, exit, and stdio close all fire, so code waiting on close hangs even though the child process and its pipes are gone.

The IPC channel slot is normally accounted for by maybeClose(), called from the channel's EOF handler, but that path is never reached when the parent closes the channel itself: _disconnect()'s finish() closed the channel and emitted 'disconnect' without calling maybeClose(), so _closesGot never reached _closesNeeded and the close event was lost.

This change counts the channel closure in finish() after emitting 'disconnect'. The EOF handler now performs that accounting only when _disconnect() was deferred by a pending handle queue (the case where the child exits before the queue drains), so each channel closure is still counted exactly once and the EOF path plus exit-before-close ordering are preserved.

Regression test test/parallel/test-child-process-disconnect-close.js asserts that close is emitted exactly once with (0, null) after a parent-initiated disconnect(); it fails on current main and passes with this change. The full test/parallel/test-child-process-*.js suite passes locally.

Fixes: #65646

@nodejs-github-bot nodejs-github-bot added child_process Issues and PRs related to the child_process subsystem. needs-ci PRs that need a full CI run. labels Sep 16, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Welcome to Node.js, and thank you for your first contribution!

Before review, please take a moment to read:

Please make sure every commit is signed off. For a first pull request, GitHub Actions require collaborator approval and Jenkins CI must be started by a collaborator or triager, so an initial wait is normal.

The 'close' event was not emitted when the parent called subprocess
disconnect() before the channel reached EOF. _disconnect()'s finish()
closed the channel and emitted 'disconnect' but never accounted for the
channel closure with maybeClose(), so _closesGot never reached
_closesNeeded and the 'close' event was lost.

Account for the channel closure in finish() and defer that accounting to
the EOF handler only when _disconnect() was deferred by a pending handle
queue, to avoid double counting.

Fixes: nodejs#65646
Signed-off-by: Rasad Regmi <regmirasad53@gmail.com>
@rasadregmi
rasadregmi force-pushed the fix/child-process-close branch from f67d655 to a6168c1 Compare September 16, 2026 16:11
@rasadregmi rasadregmi closed this Sep 16, 2026
@rasadregmi

Copy link
Copy Markdown
Author

Closing in favor of #65665 which addresses this more thoroughly, including handle queue cleanup.

@rasadregmi
rasadregmi deleted the fix/child-process-close branch September 16, 2026 16:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

child_process Issues and PRs related to the child_process subsystem. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

child_process: parent disconnect() suppresses 'close' after exit on v22, v24, and v26

2 participants