fix: prevent duplicate process.exit() on concurrent unhandledRejections#9751
Open
Gopi-Agasthia-S-005CIU744 wants to merge 1 commit into
Open
fix: prevent duplicate process.exit() on concurrent unhandledRejections#9751Gopi-Agasthia-S-005CIU744 wants to merge 1 commit into
Gopi-Agasthia-S-005CIU744 wants to merge 1 commit into
Conversation
When multiple package downloads time out simultaneously (e.g. from a private Artifactory registry), each ETIMEDOUT rejection fires an unhandledRejection event. Without a re-entrancy guard, each call to #handleExit queues its own process.exit() via the deferred stderr/stdout write-callback chain. The second process.exit() fires after #exited has already been reset by the first, causing #handleProcessExit to log "Exit handler never called!". Fix by returning early in #handleExit when #exited is already true so only the first rejection ever schedules a process.exit().
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When multiple package downloads time out simultaneously (e.g. from a private
Artifactory registry), Node.js fires multiple
unhandledRejectionevents inquick succession. Each one enters
#handleExit, which defersprocess.exit()via a
stderr.write → stdout.writecallback chain.Without a re-entrancy guard, both deferred callbacks complete independently:
#exited = true, queues a deferredprocess.exit().#handleExitbefore any I/O callback has run,sets
#exited = trueagain, queues a second deferredprocess.exit().process.exit()fires → emits'exit'→#handleProcessExitAndResetresets
#exitedback tofalse.process.exit()fires → emits'exit'→#handleProcessExitsees#exited === false→ logs "Exit handler never called!".Fix adds a two-line re-entrancy guard at the top of
#handleExitso only thefirst rejection ever schedules a
process.exit().The regression test defers
stderr.writeviasetImmediateto open the samerace window that real I/O creates in production, fires two
unhandledRejectionevents synchronously, and asserts
process.exit()was called exactly once.The test fails without the fix and passes with it.
References
Fixes #9739