Open imanushin opened 4 years ago
I suspect inherting from Exec
won't be enough to solve this as there's an open issue that matches this https://github.com/gradle/gradle/issues/7603.
To solve it we probably need to start npm
through node
rather than relying on npm.cmd
Agree, that problem won't be fixed just after task inheritance change. However after this change we can just wait for fix from Gradle team. E.g. for current moment issue will exist even if Gradle team fixes Exec
task behavior.
I'm pretty sure they both share the same issue and will be fixed at the same time, but if it's only fixed in Exec
it's probably going to be easy to also get that fix for project.exec
.
@deepy , as @philiparvidsson said here:
my bad - I edited the original post to clarify! You are correct in that it only affects bat-files.
Therefore, I can advice the following solutions:
npm.ps1
, instead of npm.bat
).npm.cmd
file inside the plugin. It means that we start node executable directly, without cmd
shell in the middle.Pretty sure that'd have the same issue. https://github.com/gradle/gradle/issues/7603#issuecomment-448963470
Thank you for the elaborate investigation! So we'd see similar issues if a program forked with
exec()
forked another program on Windows.cmd
is just a common example of this situation.
Any update on that issue ?
This really depends on the linked Gradle issue, which sounds like it should be easy to do with Java 9+.
The best way to get this fixed would be to send a PR to Gradle
Hi! The referenced Gradle issue only relates to Windows. However, I am also experiencing this bug on Linux: When I stop the Gradle task serving my docz site, the node processes are not killed. Does this mean that the Gradle issue also applies to Linux or might there be something that can be fixed in this plugin?
I might be wrong here, but I was under the impression that it applied to all operating systems. At least I've seen similar issues on macOS and Linux
Hm, seems you are right. The original issue stated that
NOTE 1: This seems to affect Windows only!
But the latest commenter reproduced the issue on macOS. So it will likely be the same on Linux.
Regarding the platform: I have the same issue on linux with gradle and webpack.
I also managed to reproduce this both on macOS and Linux. As a workaround, I kill the started node process (based on the port) besides stopping the Gradle daemon.
I can provide information that may help to solve this issue.
We also encountered this problem. We use the Gradle Node plugin with yarn to run vite to serve a frontend during development time. Maybe, the following information does also apply to npm.
In our tests, we only checked Linux so far, but the information may help to check this also for other platforms.
We also encountered the described issue, but strangely, one colleague did not encounter the issue. We compared a plethora of Gradle, Node, etc. related settings and found no difference.
However, we found out the following:
To start vite
, yarn does not do this directly but by utilizing a shell. Node uses a hard-coded path for that, for Linux-like systems this is /bin/sh
(a colleague checked that by looking into the sources).
As you may know, sh
is gone since long, and today's systems provide /bin/sh
only as a link to a
sh
-compatible successor. On Ubuntu, Mint and probably other Debian-based systems, this typically is Dash. On Arch Linux, this typically is Bash.
Dash creates a child process for the above mentioned call. Killing the host process (via ^C
, "Stop" button in your IDE, or else) does not kill the child process, so node
(ultimately vite
) continues to run.
On the contrary, Bash does not create a child process and replaces itself by the program to run (the node
call). You can tell that by the bash
process vanishing from the system's process list. Thus, a kill does actually kill the node
process.
This issue can be solved by having Bash installed and explicitly setting it as the shell to use, like so:
yarn config set "script-shell" "/usr/bin/bash"
.
npm has such a setting, too.
So, people affected by this issue may try the above mentioned or at least check which shell is used as the link target of sh
.
Any update on this one ?
Thanks @buergerj, for the workaround. I can confirm that it works on my Linux machine (with the slight change to use the path /bin/bash
where bash
is available on my system).
Just a reminder that this should be fixed in Gradle itself
Thanks @buergerj for the workaround, it helped me solve a weeklong issue! 🙏I managed to figure out Dash was the likely cause but didn't know it spawned child process and that Bash doesn't.
Another thanks to @buergerj for the config workaround. To keep the installation more self-contained and avoid a separate yarn config set
command I opted to:
Here is my workaround (on Windows):
For running tasks during development outside of the normal build flow (such as npm start
, npm install
) I use a wrapper batch file that directly calls the downloaded installation of node/npm, skipping Gradle and thus the wrapped process issue. A couple additional benefits:
A couple downsides:
NpmTask
dependencies in the build are wired up correctly to be executed as part of a "real" build, but this is probably already the case in a well-behaved build. For me, this is really just npm install
-> npm run build
.npm.bat
instead of npm
. I'm happy with tab completion, but there are probably better solutions.The creation of the wrapper batch file can be automated with a Gradle task:
def npmShortcutPath = 'npm.bat'
task npmShortcut {
dependsOn nodeSetup
inputs.property 'nodeVersion', nodeVersion
outputs.file npmShortcutPath
doLast {
def nodeDir = nodeSetup.nodeDir.get()
def contents = "@echo off\n${nodeDir}\\nodevars.bat && npm.cmd %*\n"
file(npmShortcutPath).text = contents
}
}
tasks.named('npmSetup') {
finalizedBy npmShortcut
}
Add npm.bat
to .gitignore
. Something similar can be done for npx
as well.
any updates ?
@amir1376 this is https://github.com/gradle/gradle/issues/7603
I also recently encountered this issue and I made a custom workaround based on Gradle Shared Build Services (https://docs.gradle.org/current/userguide/build_services.html). The idea is that the service is attached to npm tasks and kills them properly (i.e. also killing dependents processes) in case the Gradle task is stopped. If it may be of any use to someone else, I made a small Gradle plugin for it https://github.com/PeredurOmega/GradleNpmPlugin mainly resolving this issue + automatically defining tasks for scripts defined in package.json.
Three years later and this is still an issue... @buergerj how do I try what you're talking about, from within my build.gradle for npm? Are there any other workarounds that involve just changing/setting something in the build.gradle?
I get how frustrating this can be, but this is really an issue that needs to be solved upstreams as this is caused by a bug in Gradle If you're comfortable working on solving the issue there's https://github.com/gradle/gradle/pull/18756 which needs a little extra work, otherwise I'll also be happy to include workarounds in the plugin provided they can be tested and toggled by a feature flag
I get that it's an upstream issue and sorry if I came off annoyed with anyone here. Strange and more people aren't complaining about this issue as it affects both Windows and Linux, and I would have to guess more than just this plugin, which I love because the less I have to deal with frontend tools the better.
I was just hoping I could get more details on how to get the workaround talked about, and if I could set up that workaround in my build.gradle for npm. If the workaround involved actually installing node/npm that would kind of defeat the purpose of the plugin for me, then my workaround would just be to have a process window up, and kill the process manually when I'm done.
I would not be comfortable working on it as I don't have a Windows machine(haven't for years), so I could only test the Linux path at best.
Just want to add that the underlying issue for this can be reproduced on Linux and macOS as well, but due to the way node is packaged it will only affect Windows users Giving a 👍 on the issue in the gradle repository is a good way to signal that you're affected (and helps with prioritization)
Seems like this could be resolved at least partially by #228 if it implements autocloseable, right? This is what https://github.com/node-gradle/gradle-node-plugin/issues/65#issuecomment-1442107492 does.
Unfortunately the build services work has stalled due to https://github.com/gradle/gradle/issues/17559 🥲 But the underlying Gradle issue would still affect us no matter which solution is picked, the way to work around it would be to implement the process tracking in the plugin itself and that's a too large scope for the current team
Short: stopping gradle execution on Windows from command line by pressing
Ctrl-C
doesn't lead to stoppingnode.exe
subprocess on Windows.Steps to reproduce:
start
atpackage.json
script via:npmStart
task via gradle kts script:.\gradlew.bat :npmStart
Ctrl-C
to stopnode.exe
executionExpected result: All child processes under
gradle
will be stopped.Actual result:
Node.exe
process remains. And this process starts to be zombie, e.g. process without parent.Hint: probably (I'm not sure, this require testing),
NpmTask
should be inherited fromExec
, not from DefaultTask. It means thatargs
field will be inherited fromExec
task, so it will be fully configurable via user. However nextGradle
tool will be responsible to stop all child tasks.