[BUGFIX #7924] Fix Race in yarn pack
stream code
#8190
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.
TODO:
In some versions of Node.js which include nodejs/node@0e89b64 (such as 12.16.2) ,
yarn pack
no-longer runspostpack
. Debugging the code in question (following example) lead us to notice that the followingawait
never progressed, the streamserror
andclose
handlers were never invoked, and that the process was appearing to exit prematurely.What is going on here?
As it turns out, the above stream code is unsafe, and only appeared to function do to a specific implementation detail of
zlib.Gzip
. Once that implementation detail changed in Node.js; the process would exit while awaiting the above promise, and thus would leave the code which triggers thepostpack
hook unreachable.The facts (As we know them so far):
zlib.Gzip
added a task to the event queueyarn pack
would exit prior to invoking thepostpack
hook.Mystery solved!
That's a lot going on, so how can one safely use streams ?
Luckily Node.js has a new utility method (node >= 10)
const { pipeline } = require(‘stream’);
This higher level utility has less caveats thanstream.pipe
/stream.on(…)
and appears to be preferred in Node.js's own documentation has been re-worked to usepipeline
for all but the most specific low level operations.In short, rather then:
Under most circumstances it is likely wise to use
And if you are using streams with promises, consider first promisifying
pipeline
@krisselden provided validation of the issue, updated my mental model of streams and ultimately the appropriate most resilient solution.