-
-
Notifications
You must be signed in to change notification settings - Fork 217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Windows: execa leaving processes around when running npm scripts in a sh shell #433
Comments
Hi @ManiacDC, Thanks for reporting this. It seems that the problem is due to the
const childProcess = require('child_process')
childProcess.spawn('npm', ['run', 'tsc'], { stdio: 'inherit' }) You would receive the following error message (on Windows only):
Instead, npm requires using childProcess.spawn('npm', ['run', 'tsc'], { stdio: 'inherit', shell: true }) (Note: If you specify a shell file (as opposed to a binary), on Windows, and do not use the By default, Execa terminates the child process when its parent process terminates using something similar to: const childProcess = require('child_process')
const spawned = childProcess.spawn('npm', ['run', 'tsc'], { stdio: 'inherit', shell: true })
process.on('exit', () => { spawned.kill() }) Note that there are four processes here: The problem in your case seems to be related to the Could you please try to pass the The problem can be reproduced with the following code (which overly simplifies what Execa does under the hood): const childProcess = require('child_process')
const spawned = childProcess.spawn('npm', ['run', 'tsc'], { stdio: 'inherit', shell: true, windowsHide: true })
process.on('exit', () => { spawned.kill() }) The
@sindresorhus What are your thoughts on this? |
I should point out that lerna is uses shell: true, though I didn't think it made a difference since the issue occurred with or without it. I tested with all 3 of those settings, and that did indeed fix the problem with my reproduction script. I tried tweaking lerna to fix this briefly, but wasn't able. On Monday I'll spend some more time trying to incorporate this into a build of lerna to see if that addresses the issue there (it may be the version of execa its using - 1.0.0 - doesn't have the mentioned flags). Thanks so much for your help on this. |
It seems weird to switch NodeJS's default value for windowHide. Is there a discussion on why this was done? In regards to fixing this in dependent packages... Lerna, for example, calls execa in 57 different places, so changing windowHide back to false would be problematic. Would execa devs be open to something like: execa.defaultOptions = {windowHide: false}; Then a small change here: Line 45 in 26d6b0d
From
to
|
I hear you, especially the fact that this is difficult to change when Some additional issues and discussions about the
While I see how changing the default of I think (as a Linux user) I am missing some in-depth knowledge of the Windows API to make a good judgment here. I am also not sure if one of the Node.js bugs mentioned above is the actual source of the problem. My initial feeling would be to change the default value of However, I would be interested to know @sindresorhus feedback on this, as he has more insights into it. Note: I would personally discourage allowing customizing Execa default options with the intent to change how one's dependencies are using Execa. This would imply trying to change how one's dependency is using its own code/dependencies, which does not seem like a pattern we should encourage as it breaks encapsulation. That being said, there might be alternative solutions that would solve the same underlying problem, such as changing the default value of that option. |
It's been a while, but the way I remember the Windows API to function is that use use CREATE_NO_WINDOWS when launching a console application from a non-console application to prevent the creation of a console window. When launching one console application from another, that does not create additional windows. This is confirmed by the option CREATE_NEW_CONSOLE which states: The new process has a new console, instead of inheriting its parent's console (the default). The only issue is when PROCESS_DETACHED is specified because you cannot use that in conjunction with either CREATE_NO_WINDOW or CREATE_NEW_CONSOLE. So, "windowsHide" would make sense for, as an example, Electron apps because they are not GUI applications. When running node from another console application, the option is meaningless. By allowing a tool like Lerna to set the default option itself without having to specify it in every invocation, it allows those tools to expose that functionality to us. For example: "lerna --gui" might set the default to |
Users will complain either way. If we change the default, it will be a disruptive and breaking change for many users. There is no clear win-win situation as far as I can see. I don't use Windows and I'm honestly a bit burned out of having to spend so much time in general (for all my projects) working around Windows deficiencies. |
My suggested change would not actually change the default. It would allow
the tools (ex. Lerna) to change to the default for their application. This
would not affect any existing software but would allow us to work with
Lerna to get an option exposed on their end that would be easy to implement.
…On Sun, Aug 16, 2020 at 7:34 AM Sindre Sorhus ***@***.***> wrote:
Users will complain either way. If we change the default, it will be a
disruptive and breaking change for many users. There is no clear win-win
situation as far as I can see.
I don't use Windows and I'm honestly a bit burned out of having to spend
so much time in general (for all my projects) working around Windows
deficiencies.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#433 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABT6LNWBQD6RS732UZ3YJF3SA674VANCNFSM4P7YKEWA>
.
|
I agree with @raijinsetsu 's suggestion. It allows applications to set the default for themselves, and the applications are really the only ones that can know the proper way to launch these new processes. |
@ehmicky after some more testing, I realized that 'windowsHide: false' setting only fixes the "node test.js" case (which is NOT the case lerna falls into). The "sh -c 'node test.js'" and "./launch.sh" cases still leave the orphaned process around. Worth noting, "node test.js" launches the parent node.exe process with winpty.exe, but the other 2 launch the parent node.exe process with sh.exe. I'm wondering if this is a git-for-windows/msys2 issue at this point :/ |
While the @sindresorhus I have been searching core Node.js issues about
It looks like no users has opened any issues for changing the default value to If I take @raijinsetsu comment:
This would mean spawning a non-console process from another non-console process would not create a new console window, even if The initial discussions in Node.js core were not mentioning the child processes termination problem, since that termination logic is an Execa-specific feature. To me, it seems that, when added to the points above, changing the default value of However, I think @sindresorhus you've got some good points above, so if the points above are still not convincing you, I'd suggest keeping |
I suspect all the ways that does not use the Job Object in Windows are hacks that will fail under some circumstances. Raymond Chen is old time Microsofter who explains how to clean up child processes correctly with Windows in this article. I'm pretty certain that any other way of doing it is not guaranteed by the Windows OS to kill the child processes. That is the canonical way to start child processes so that they are also killed if parent process dies. |
…t properly. plugin-run-script and plugin-build script use execa.command with the shell: true option set to execute the user's command. On Windows, this causes the child process to remain running after Snowpack exits: sindresorhus/execa#433. The fix is to override the default windowsHide option -- as Snowpack always runs from a console we don't actually need execa to hide any extra console windows for us.
…t properly. (#1022) plugin-run-script and plugin-build script use execa.command with the shell: true option set to execute the user's command. On Windows, this causes the child process to remain running after Snowpack exits: sindresorhus/execa#433. The fix is to override the default windowsHide option -- as Snowpack always runs from a console we don't actually need execa to hide any extra console windows for us.
`execa` defaults to `windowsHide: true`, which prevents child processes from terminating child processes on exit [1]. Let's set `windowsHide: false` to terminate child processes properly on exit. [1]: sindresorhus/execa#433
Our group uses lerna to execute npm scripts in our packages, and lerna in turn uses execa (albeit an old version, but my reproduction uses the current version) to execute the npm scripts. We've set npm to use "sh" as our default shell so that programmers working on multiple platforms can use the same scripts. The below issue has become a major roadblock for our work.
We've run into an issue where node.exe processes are left around when terminating the main process - execa is not cleaning up the full process tree. This happens on Windows, when "sh" is the shell npm is set to use, and the script loops infinitely until terminated (such as 'tsc -w'). To make sure this is clear, it does NOT happen when running 'npm run' directly, only when run from execa.
I've created a simple tool to reproduce this (modified from Ciantic's work for issue #429 ):
https://github.com/ManiacDC/execa-npm-sh-issue
Please see the readme for instructions and expected results.
This may or may not be related to issue #429 , though it's definitely similar in ways.
The text was updated successfully, but these errors were encountered: