Repository navigation
fix: deliver pending utilityProcess messages before emitting exit - #54924
Conversation
HandleTermination closed the parentPort connector before emitting 'exit', so messages the child had posted but the browser had not dispatched yet were dropped. The connector dispatches one message per task, and the exit notification can already be queued ahead of those tasks, so a child that posts several messages and then calls process.exit() lost all but the first. Dispatch whatever is already queued on the port before closing it. Browser shutdown still closes the port without dispatching, since the child is still running then. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LPMvJBQiyP6b7QjatACmnS
dsanders11
left a comment
There was a problem hiding this comment.
@claude, since #54901 landed can you fold the change mentioned in https://github.com/electron/electron/pull/54901/changes#r4274263333 into this PR?
Move the Atomics.wait() call in the utilityProcess message-before-exit test into a documented sleepSync() spec helper. With pending parentPort messages now dispatched before 'exit', the api-net-spec.js fixture can post its result and exit right away again, so remove the ack handshake that #54901 added as a workaround, along with the error logging that covered the wait for the ack. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LPMvJBQiyP6b7QjatACmnS
|
Addressed in 5b92d8c (after merging main to pick up #54901):
On Generated by Claude Code |
|
Release Notes Persisted
|
|
I was unable to backport this PR to "42-x-y" cleanly; |
|
I was unable to backport this PR to "43-x-y" cleanly; |
|
I was unable to backport this PR to "45-x-y" cleanly; |
|
I was unable to backport this PR to "44-x-y" cleanly; |
|
claude[bot] has manually backported this PR to "43-x-y", please check out #54962 |
…4960) fix: deliver pending utilityProcess messages before emitting exit (#54924) * fix: deliver pending utilityProcess messages before emitting exit HandleTermination closed the parentPort connector before emitting 'exit', so messages the child had posted but the browser had not dispatched yet were dropped. The connector dispatches one message per task, and the exit notification can already be queued ahead of those tasks, so a child that posts several messages and then calls process.exit() lost all but the first. Dispatch whatever is already queued on the port before closing it. Browser shutdown still closes the port without dispatching, since the child is still running then. Claude-Session: https://claude.ai/code/session_01LPMvJBQiyP6b7QjatACmnS * test: extract sleepSync helper and drop utility-process ack handshake Move the Atomics.wait() call in the utilityProcess message-before-exit test into a documented sleepSync() spec helper. With pending parentPort messages now dispatched before 'exit', the api-net-spec.js fixture can post its result and exit right away again, so remove the ack handshake that #54901 added as a workaround, along with the error logging that covered the wait for the ack. Claude-Session: https://claude.ai/code/session_01LPMvJBQiyP6b7QjatACmnS (cherry picked from commit 4a802b0) Claude-Session: https://claude.ai/code/session_01LPMvJBQiyP6b7QjatACmnS Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
HandleTermination closed the parentPort connector before emitting 'exit', so messages the child had posted but the browser had not dispatched yet were dropped. The connector dispatches one message per task, and the exit notification can already be queued ahead of those tasks, so a child that posts several messages and then calls process.exit() lost all but the first. Dispatch whatever is already queued on the port before closing it. Browser shutdown still closes the port without dispatching, since the child is still running then. Also extract a sleepSync helper for the new spec, and drop the utility-process ack handshake that #54901 added as a workaround, since pending parentPort messages are now dispatched before 'exit'. Manual backport of #54924. Conflicts resolved: the header only adds the DispatchPendingMessages() declaration (43-x-y has no CloseStdioReadFds()), and the spec imports sleepSync into 43-x-y's existing spec-helpers import. (cherry picked from commit 4a802b0) (cherry picked from commit 53d6d27) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LPMvJBQiyP6b7QjatACmnS
|
claude[bot] has manually backported this PR to "42-x-y", please check out #55000 |
…4962) HandleTermination closed the parentPort connector before emitting 'exit', so messages the child had posted but the browser had not dispatched yet were dropped. The connector dispatches one message per task, and the exit notification can already be queued ahead of those tasks, so a child that posts several messages and then calls process.exit() lost all but the first. Dispatch whatever is already queued on the port before closing it. Browser shutdown still closes the port without dispatching, since the child is still running then. Also extract a sleepSync helper for the new spec, and drop the utility-process ack handshake that #54901 added as a workaround, since pending parentPort messages are now dispatched before 'exit'. Manual backport of #54924. Conflicts resolved: the header only adds the DispatchPendingMessages() declaration (43-x-y has no CloseStdioReadFds()), and the spec imports sleepSync into 43-x-y's existing spec-helpers import. (cherry picked from commit 4a802b0) (cherry picked from commit 53d6d27) Claude-Session: https://claude.ai/code/session_01LPMvJBQiyP6b7QjatACmnS Co-authored-by: Claude <noreply@anthropic.com>
…5000) HandleTermination closed the parentPort connector before emitting 'exit', so messages the child had posted but the browser had not dispatched yet were dropped. The connector dispatches one message per task, and the exit notification can already be queued ahead of those tasks, so a child that posts several messages and then calls process.exit() lost all but the first. Dispatch whatever is already queued on the port before closing it. Browser shutdown still closes the port without dispatching, since the child is still running then. Also extract a sleepSync helper for the new spec, and drop the utility-process ack handshake that #54901 added as a workaround, since pending parentPort messages are now dispatched before 'exit'. Manual backport of #54924. Conflicts resolved: the header only adds the DispatchPendingMessages() declaration (42-x-y has no CloseStdioReadFds()). The spec's sleepSync import merged cleanly into 42-x-y's existing spec-helpers import. (cherry picked from commit 4a802b0) (cherry picked from commit 53d6d27) Claude-Session: https://claude.ai/code/session_01LPMvJBQiyP6b7QjatACmnS Co-authored-by: Claude <noreply@anthropic.com>
process.exit() does not wait for pending postMessage() writes, so a utility child that exits right after posting can lose its message. Restore the acknowledgement handshake that #54924 removed from the api-net fixture and helper, and add it to the env-app and js2c-code-cache fixtures, so those children only exit once the parent has acknowledged their message. The #54924 test no longer posts right before exiting. The child posts its parentPort messages, then posts on a transferred MessagePortMain and exits only when the parent replies there. parentPort and the port share the same ordered Mojo channel, so all of the parentPort messages have reached the parent when the port message does. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LPMvJBQiyP6b7QjatACmnS
process.exit() does not wait for pending postMessage() writes, so a utility child that exits right after posting can lose its message. Restore the acknowledgement handshake that #54924 removed from the api-net fixture and helper, and add it to the env-app and js2c-code-cache fixtures, so those children only exit once the parent has acknowledged their message. The #54924 test no longer posts right before exiting. The child posts its parentPort messages, then posts on a transferred MessagePortMain and exits only when the parent replies there. parentPort and the port share the same ordered Mojo channel, so all of the parentPort messages have reached the parent when the port message does. Claude-Session: https://claude.ai/code/session_01LPMvJBQiyP6b7QjatACmnS Co-authored-by: Claude <noreply@anthropic.com>
process.exit() does not wait for pending postMessage() writes, so a utility child that exits right after posting can lose its message. Restore the acknowledgement handshake that #54924 removed from the api-net fixture and helper, and add it to the env-app and js2c-code-cache fixtures, so those children only exit once the parent has acknowledged their message. The #54924 test no longer posts right before exiting. The child posts its parentPort messages, then posts on a transferred MessagePortMain and exits only when the parent replies there. parentPort and the port share the same ordered Mojo channel, so all of the parentPort messages have reached the parent when the port message does. Claude-Session: https://claude.ai/code/session_01LPMvJBQiyP6b7QjatACmnS Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
process.exit() does not wait for pending postMessage() writes, so a utility child that exits right after posting can lose its message. Restore the acknowledgement handshake that #54924 removed from the api-net fixture and helper, and add it to the env-app and js2c-code-cache fixtures, so those children only exit once the parent has acknowledged their message. The #54924 test no longer posts right before exiting. The child posts its parentPort messages, then posts on a transferred MessagePortMain and exits only when the parent replies there. parentPort and the port share the same ordered Mojo channel, so all of the parentPort messages have reached the parent when the port message does. Claude-Session: https://claude.ai/code/session_01LPMvJBQiyP6b7QjatACmnS Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
process.exit() does not wait for pending postMessage() writes, so a utility child that exits right after posting can lose its message. Restore the acknowledgement handshake that #54924 removed from the api-net fixture and helper, and add it to the env-app and js2c-code-cache fixtures, so those children only exit once the parent has acknowledged their message. The #54924 test no longer posts right before exiting. The child posts its parentPort messages, then posts on a transferred MessagePortMain and exits only when the parent replies there. parentPort and the port share the same ordered Mojo channel, so all of the parentPort messages have reached the parent when the port message does. Claude-Session: https://claude.ai/code/session_01LPMvJBQiyP6b7QjatACmnS Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
process.exit() does not wait for pending postMessage() writes, so a utility child that exits right after posting can lose its message. Restore the acknowledgement handshake that #54924 removed from the api-net fixture and helper, and add it to the env-app and js2c-code-cache fixtures, so those children only exit once the parent has acknowledged their message. The #54924 test no longer posts right before exiting. The child posts its parentPort messages, then posts on a transferred MessagePortMain and exits only when the parent replies there. parentPort and the port share the same ordered Mojo channel, so all of the parentPort messages have reached the parent when the port message does. Claude-Session: https://claude.ai/code/session_01LPMvJBQiyP6b7QjatACmnS Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
Requested by John Kleinschmidt · Slack thread
Description of Change
UtilityProcessWrapper::HandleTerminationclosed theparentPortconnector before emitting'exit', so messages the child had already posted but the main process had not dispatched yet were dropped. The connector dispatches one message per task, and the child's exit notification can already be queued ahead of those tasks, so a child that doesprocess.parentPort.postMessage(...)a few times and thenprocess.exit(0)loses everything after the first message. @ckerr found this while reviewing #54901, where a spec fixture needed an ack handshake to work around it. Now that #54901 has landed, this PR also removes that handshake fromspec/fixtures/api/utility-process/api-net-spec.jsandwaitForUtilityResult.This change dispatches whatever is already queued on the port before closing it, so those messages are emitted before
'exit'. It only reads messages that are already there and never blocks. Browser shutdown (Shutdown()) still closes the port without dispatching, because the child is still running at that point.The new spec has the child post 20 messages and exit while the main thread is briefly blocked. On
46.0.0-nightly.20261014it failed in all 6 runs that completed (only message 0 arrived before'exit'; 2 more runs died to an unrelated vitest worker start failure in my container). I did not compile the C++ change locally, so CI is the first build of it.Checklist
🤖 Generated with Claude Code
https://claude.ai/code/session_01LPMvJBQiyP6b7QjatACmnS
Release Notes
Notes: Fixed
utilityProcessdropping messages posted withprocess.parentPort.postMessage()right before the process exits.Generated by Claude Code