[rush] Fix issue where package.json script hangs when accessing STDIN on Windows #5579
+11
−1
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.
Summary
The problem I encountered:
rush install && rush testfrom cmd.exeThe process hangs while building
api-documenter-scenarios, which uses a Heft"run-script-plugin"to invokenode.exe api-documenter/lib/start.jsfromrunScenarios.ts. The actually hang is somewhere in API Documenter, but if you simply addconsole.log(process.stdin.isTTY)to the top ofstart.jsit will hang forever. Presumably something goes wrong during lazy initialization of theprocess.stdinproperty.Details
Probably this is ultimately another deep Node.js bug on Windows, since Windows TTY/streams has unusual semantics and the Node maintainers don't put as much effort into fixing those issues. I found several GitHub issues about stdin hangs that were opened and later closed without any code change.
A simple way to avoid the hang is to change this code:
rushstack/build-tests/api-documenter-scenarios/src/runScenarios.ts
Lines 46 to 59 in be05af7
...to use
stdio: ['ignore', 'inherit', 'inherit'].But I did not make that fix, because it seems fundamentally unreasonable. What's wrong with inheriting STDIN? And why does it only repro when invoked by Rush?
After a bunch of debugging, I realized Rush is doing something wrong:
When spawning a child process, in the case where it binds STDOUT/STDERR to
pipeto redirect the output to the stream collator, Rush also seems to bind STDIN topipe. BUT Rush never actually attaches any handlers to the STDIN stream, nor does it close it properly. This doesn't justify the specificstdin.isTTYhang, but it does open the possibility of a hang if the child process tries to read STDIN and expects it to get closed later, since it's not a TTY.Looking around in
Utilities.ts, there seem to be other copy+pastes of this same mistake, however I didn't have time to analyze them deeply. If someone else wants to suggest other fixes, that would be very welcome.How it was tested
Hang repros without the fix. Build does not hang with this fix.