electron-webpack icon indicating copy to clipboard operation
electron-webpack copied to clipboard

“electron-webpack dev” doesn’t close all child processes

Open gszy opened this issue 6 years ago • 29 comments

Steps to reproduce:

  1. clone https://github.com/electron-userland/electron-webpack-quick-start and follow installation instructions;
  2. run yarn dev.

This will start electron-webpack dev which in my case resulted in the following processes being started:

$ pstree -p 22667
node(22667)─┬─sh(22687)───node(22688)───node(22689)─┬─electron(22715)─┬─electron(22717)─┬─electron(22749)─┬─{electron}(22750)
            │                                       │                 │                 │                 ├─{electron}(22751)
            │                                       │                 │                 │                 ├─{electron}(22752)
            │                                       │                 │                 │                 ├─{electron}(22753)
            │                                       │                 │                 │                 ├─{electron}(22754)
            │                                       │                 │                 │                 ├─{electron}(22755)
            │                                       │                 │                 │                 ├─{electron}(22756)
            │                                       │                 │                 │                 ├─{electron}(22757)
            │                                       │                 │                 │                 ├─{electron}(22758)
            │                                       │                 │                 │                 ├─{electron}(22759)
            │                                       │                 │                 │                 ├─{electron}(22760)
            │                                       │                 │                 │                 ├─{electron}(22761)
            │                                       │                 │                 │                 ├─{electron}(22803)
            │                                       │                 │                 │                 ├─{electron}(22816)
            │                                       │                 │                 │                 ├─{electron}(22817)
            │                                       │                 │                 │                 ├─{electron}(22818)
            │                                       │                 │                 │                 └─{electron}(22819)
            │                                       │                 │                 ├─electron(22766)─┬─{electron}(22768)
            │                                       │                 │                 │                 ├─{electron}(22769)
            │                                       │                 │                 │                 ├─{electron}(22770)
            │                                       │                 │                 │                 ├─{electron}(22771)
            │                                       │                 │                 │                 ├─{electron}(22772)
            │                                       │                 │                 │                 ├─{electron}(22773)
            │                                       │                 │                 │                 ├─{electron}(22774)
            │                                       │                 │                 │                 ├─{electron}(22782)
            │                                       │                 │                 │                 ├─{electron}(22784)
            │                                       │                 │                 │                 ├─{electron}(22785)
            │                                       │                 │                 │                 ├─{electron}(22791)
            │                                       │                 │                 │                 ├─{electron}(22793)
            │                                       │                 │                 │                 └─{electron}(22804)
            │                                       │                 │                 └─electron(22767)─┬─{electron}(22775)
            │                                       │                 │                                   ├─{electron}(22776)
            │                                       │                 │                                   ├─{electron}(22777)
            │                                       │                 │                                   ├─{electron}(22779)
            │                                       │                 │                                   ├─{electron}(22780)
            │                                       │                 │                                   ├─{electron}(22781)
            │                                       │                 │                                   ├─{electron}(22783)
            │                                       │                 │                                   ├─{electron}(22786)
            │                                       │                 │                                   ├─{electron}(22787)
            │                                       │                 │                                   ├─{electron}(22788)
            │                                       │                 │                                   ├─{electron}(22789)
            │                                       │                 │                                   ├─{electron}(22808)
            │                                       │                 │                                   ├─{electron}(22820)
            │                                       │                 │                                   └─{electron}(22821)
            │                                       │                 ├─electron(22745)─┬─{electron}(22794)
            │                                       │                 │                 ├─{electron}(22795)
            │                                       │                 │                 ├─{electron}(22796)
            │                                       │                 │                 ├─{electron}(22797)
            │                                       │                 │                 ├─{electron}(22798)
            │                                       │                 │                 ├─{electron}(22799)
            │                                       │                 │                 ├─{electron}(22800)
            │                                       │                 │                 └─{electron}(22801)
            │                                       │                 ├─{electron}(22716)
            │                                       │                 ├─{electron}(22718)
            │                                       │                 ├─{electron}(22719)
            │                                       │                 ├─{electron}(22720)
            │                                       │                 ├─{electron}(22721)
            │                                       │                 ├─{electron}(22722)
            │                                       │                 ├─{electron}(22723)
            │                                       │                 ├─{electron}(22724)
            │                                       │                 ├─{electron}(22725)
            │                                       │                 ├─{electron}(22726)
            │                                       │                 ├─{electron}(22727)
            │                                       │                 ├─{electron}(22728)
            │                                       │                 ├─{electron}(22729)
            │                                       │                 ├─{electron}(22730)
            │                                       │                 ├─{electron}(22731)
            │                                       │                 ├─{electron}(22733)
            │                                       │                 ├─{electron}(22734)
            │                                       │                 ├─{electron}(22738)
            │                                       │                 ├─{electron}(22740)
            │                                       │                 ├─{electron}(22741)
            │                                       │                 ├─{electron}(22742)
            │                                       │                 ├─{electron}(22743)
            │                                       │                 ├─{electron}(22744)
            │                                       │                 ├─{electron}(22746)
            │                                       │                 ├─{electron}(22748)
            │                                       │                 ├─{electron}(22812)
            │                                       │                 ├─{electron}(22813)
            │                                       │                 ├─{electron}(22814)
            │                                       │                 └─{electron}(22815)
            │                                       ├─node(22701)───node(22702)─┬─{node}(22703)
            │                                       │                           ├─{node}(22704)
            │                                       │                           ├─{node}(22705)
            │                                       │                           ├─{node}(22706)
            │                                       │                           ├─{node}(22707)
            │                                       │                           ├─{node}(22708)
            │                                       │                           ├─{node}(22709)
            │                                       │                           ├─{node}(22710)
            │                                       │                           └─{node}(22711)
            │                                       ├─{node}(22690)
            │                                       ├─{node}(22691)
            │                                       ├─{node}(22692)
            │                                       ├─{node}(22693)
            │                                       ├─{node}(22694)
            │                                       ├─{node}(22695)
            │                                       ├─{node}(22696)
            │                                       ├─{node}(22697)
            │                                       └─{node}(22698)
            ├─{node}(22678)
            ├─{node}(22679)
            ├─{node}(22680)
            ├─{node}(22681)
            ├─{node}(22682)
            ├─{node}(22683)
            ├─{node}(22684)
            ├─{node}(22685)
            └─{node}(22686)

Then I closed application window and 22667 is, correctly, gone.

$ pstree -p 22667

But something still occupies my RAM and apparently that’s…

$ pstree -p 22701
node(22701)───node(22702)─┬─{node}(22703)
                          ├─{node}(22704)
                          ├─{node}(22705)
                          ├─{node}(22706)
                          ├─{node}(22707)
                          ├─{node}(22708)
                          ├─{node}(22709)
                          ├─{node}(22710)
                          └─{node}(22711)
$ ps --no-headers o command ww 22701
/bin/sh /tmp/user/…/yarn--…-…/node /home/…/electron-webpack-problem/node_modules/webpack-dev-server/bin/webpack-dev-server.js --color --env.autoClean=false --config /home/…/electron-webpack-problem/node_modules/electron-webpack/webpack.renderer.config.js

Unfortunately, SIGTERM still doesn’t close all processes:

$ pstree -p 22701
$ pstree -p 22702
node(22702)─┬─{node}(22703)
            ├─{node}(22704)
            ├─{node}(22705)
            ├─{node}(22706)
            ├─{node}(22707)
            ├─{node}(22708)
            ├─{node}(22709)
            ├─{node}(22710)
            └─{node}(22711)
$ ps --no-headers o command ww 22702
/usr/bin/node /home/…/electron-webpack-problem/node_modules/webpack-dev-server/bin/webpack-dev-server.js --color --env.autoClean=false --config /home/…/electron-webpack-problem/node_modules/electron-webpack/webpack.renderer.config.js

SIGTERMing 22702 finally frees up my RAM and gets rid of unnecessary processes.

I think that relatively long waiting period before returning to terminal prompt (where I had run yarn dev) after application window was closed may be related to the above issue.

(Node 8, GNU/Linux.)

gszy avatar Dec 20 '18 16:12 gszy

The problem has disappeared.

gszy avatar Jan 12 '19 14:01 gszy

Still happening to me on newest version, Node 10, Win10. Did you change anything?

stereokai avatar Feb 24 '19 12:02 stereokai

Probably some system update solved the problem.

gszy avatar Feb 24 '19 14:02 gszy

When I am ctrl+cing electron-webpack dev, 3 processes remain open:

  1. Electron at 100% CPU with this commandline: C:\Users\User\Dev\electron-webpack-quick-start\node_modules\electron\dist\electron.exe" --type=renderer --no-sandbox --enable-features=SharedArrayBuffer --service-pipe-token=10686501403369708028 --lang=en-US --app-path="C:\Users\User\Dev\electron-webpack-quick-start\node_modules\electron\dist\resources\default_app.asar" --node-integration=true --webview-tag=true --no-sandbox --background-color=#fff --device-scale-factor=1 --num-raster-threads=2 --enable-main-frame-before-activation --service-request-channel-token=10686501403369708028 --renderer-client-id=6 --mojo-platform-channel-handle=2008 /prefetch:1

  2. This Node.js process: C:\Program Files\nodejs\node.exe" --max-old-space-size=2048 C:\Users\User\Dev\electron-webpack-quick-start\node_modules\fork-ts-checker-webpack-plugin\lib\service.js

  3. And this Node.js process: node "C:\Users\User\Dev\electron-webpack-quick-start\node_modules\.bin\\..\webpack-dev-server\bin\webpack-dev-server.js" --color --env.autoClean=false --config C:\Users\User\Dev\electron-webpack-quick-start\node_modules\electron-webpack\webpack.renderer.config.js

stereokai avatar Feb 24 '19 15:02 stereokai

@develar Please see my last comment here. Thanks!

stereokai avatar Feb 27 '19 14:02 stereokai

Same thing here node v8.9.4 though. Gets quite annoying after a while.

Smiche avatar May 16 '19 08:05 Smiche

UP! after aborting process electron-webpack dev doesn't dev-server process doesn't kill

AniMeIIIkA avatar Jun 04 '19 12:06 AniMeIIIkA

@fabiospampinato @loopmode @develar Please address!

stereokai avatar Jun 05 '19 12:06 stereokai

I can replicate this issue on windows, Node 12

Mike-Dax avatar Jun 05 '19 12:06 Mike-Dax

@stereokai I do not maintain this repo, and this issue hasn't caused any troubles to me yet. You'd have better chances to get this fixed by submitting a PR.

fabiospampinato avatar Jun 05 '19 12:06 fabiospampinato

@fabiospampinato, sure! Can you please look at my comment above and see maybe you have some insight into what I shared there?

stereokai avatar Jun 05 '19 13:06 stereokai

I once looked into this issue and I had the feeling that we're not sending the right signal - SIGINT, and that maybe we need to use SIGTERM instead. However, then I saw that it's only used on Linux while I experience the issue on windows. Since this only happens in development - at least for me - I gave up on this and wrote a short script to kill the processes manually instead. I can share it if someone is interested.

Nonetheless, the issue is still there and unsolved. If somebody got the time, it must be something in https://github.com/electron-userland/electron-webpack/blob/master/packages/electron-webpack/src/dev/ChildProcessManager.ts (I think so at least). I wouldn't bother rebuilding and testing, but instead just hack ChildProcessManager.js inside node_modules until the culprit is found. However I have no time at all for it, these days :(

loopmode avatar Jun 05 '19 15:06 loopmode

That's a great starting point, I'll try to make time for this soon

stereokai avatar Jun 06 '19 10:06 stereokai

node_modules\electron-webpack\out\dev\ChildProcessManager.js line 84 SIGINT to SIGTERM node_modules\electron-webpack\out\dev\dev-runner.js line 326 SIGINT to SIGTERM

Seems to get rid of the issue. Not sure this is the proper fix for it though.

Smiche avatar Jun 07 '19 08:06 Smiche

Nevermind this seems to resolve only Electron hanging. Or at least it still keeps nodejs process hanging if stopped with ctrl+c.

Smiche avatar Jun 07 '19 10:06 Smiche

i use this workaround in dev:

import shell from 'node-powershell';

app.on('window-all-closed', async () => { if (isDevelopment) { await killElectronWebpackDevServer(); } app.quit(); });

const killElectronWebpackDevServer = async () => { let ps = new shell({ executionPolicy: 'Bypass', noProfile: true }); ps.addCommand('wmic Path win32_process Where "CommandLine Like \'%webpack-dev-server%\'" Call Terminate'); try { await ps.invoke(); } // eslint-disable-next-line no-empty catch (e) { } }

AniMeIIIkA avatar Jun 07 '19 10:06 AniMeIIIkA

For development on Windows I use this alias in .bashrc:

kill() {
    local name="${1}"
    if [ -z "$name" ];
    then
        echo ">> Enter a process name and press [ENTER] (partial matching)"
        read name
    fi
    
    wmic process where "name like '%$name%'" delete
}

Then I go kill electron && kill cmd after stopping via Ctrl+C. (The cmd processes get stuck as well somehow, and I think it is more than one)

loopmode avatar Jun 07 '19 10:06 loopmode

At least with the current versions of NodeJS (12.4.0), I no longer have this issue if I modify run in ChildProcessManager.ts (just use a normal spawn call instead of routing through runnerw.exe) and remove the child.stdin!!.end(Buffer.from([5, 5])) and simply call child.kill('SIGINT') normally.

ghost avatar Jun 13 '19 21:06 ghost

I can confirm what @glek said.

Dropping the isWin conditionals in ChildProcessManager and using the simple way - spawn(program, args, options) and child.kill("SIGINT") - solves the issues and leads to a much improved performance and responsiveness. The processes are closed properly.

Not sure whether this can lead to other problems - I've read somewhere that child.kill on windows doesn't emit any signals/messages but just kills immediatly, not allowing listeners/observers to handle it,

@develar do you remember the motivation behind using runnerw.exe for launching and child.stdin!!.end(Buffer.from([5, 5])) for exiting? Dropping them would simplify the codebase in a nice way and properly kill the background processes at the right time. Seems like a win-win?

loopmode avatar Jul 09 '19 06:07 loopmode

emit any signals/messages but just kills immediatly, not allowing listeners/observers to handle it,

yep, runnerw adds signal handling.

develar avatar Jul 09 '19 07:07 develar

So the question is how relevant signal handling in development on windows is..

Right now, frequently starting and stopping dev environment eats up resources. When I start noticing my notebook fan spinning loudly, I go kill the processes and continue working, but it does suck..

Maybe I'll find something about using runnerw.exe in a better way, maybe we can keep it and get rid of the problem.

Otherwise, I'd suggest..we make it's usage opt-in. Disable by default, and if some use case requires it to avoid e.g. data corruption, the user can enable it via some env variable, e.g. ELECTRON_WEBPACK_USE_RUNNERW

loopmode avatar Jul 09 '19 09:07 loopmode

That sounds like a reasonable approach, @loopmode

stereokai avatar Jul 17 '19 05:07 stereokai

By "adds signal handling" what does this practically mean?

If we don't have runnerw signal handling what does that mean for us. Does that mean that we have to add some more code to electron-webpack to handle the signals ourselves?

I'm also a little bit confused where runnerw.exe comes from. From my searches all I can tell is that it was developed by Jetbrains for use in their products. Is this true?

It would just be a little bit helpful to have some context about this @develar @loopmode

Thanks!

PS as a sidenote...

My current workaround is having two scripts in package.json as follows:

    "clean-dev-win": "taskkill /f /im node.exe",
    "clean-dev-mac": "sudo killall -9 node",

Which I run depending on which OS I'm on. This could be turned into a JS script easily but it works well enough for me.

b-zurg avatar Jan 20 '20 13:01 b-zurg

@b-zurg I am as confused as you are :) I was also searching for runnerw via Google and didn't find anything solid (besides what you report).

In the "naive" tests that I made - actual dev workflow on a real project - I couldn't see any downsides from removing runnerw. I was happy to see that Ctrl+C (in Git bash, that is) worked like a charm - real fast and snappy, and also killing all child processes.

What I did not try out tho, now that I think about it, was using Windows CMD or Powershell. Maybe runnerw is some kind of broker for cmd.exe, so that it can work with the signals. Maybe worth checking.

I'm just a regular user of electron-webpack, but if it was my decision, I'd drop this runnerw thing entirely out of the project. That resolves a bunch of issues. Then wait if new issues arise..

Btw @b-zurg , in my experience, many cmd processes stay alive (webpack I believe), and just killing node doesn't help in many cases. Killing cmd in addition does help then.

loopmode avatar Jan 22 '20 11:01 loopmode

I also think perhaps runnerw could be entirely replaced. It just requires some time and some good test cases, neither of which I have at the moment 🤷‍♂️

I have a pretty good temporary solution though for now, though it requires the use of tree-kill and execa both of which are pretty well-maintained libraries.

const execa = require("execa");
const treeKill = require("tree-kill");

const subProcess = execa("electron-webpack", ["dev"]);
subProcess.stdout.pipe(process.stdout);
subProcess.stderr.pipe(process.stderr);

process.on("SIGINT", async () => {
  console.log("Caught interrupt. Killing process tree");
  treeKill(subProcess.pid, (e) => {
    console.error(`Tree Kill failed because of ${e}`);
  });
});

This code is saved in (for example) ./scripts/devrunner.js.

Then in my package.json I have the following line in scripts:

"dev": "node ./scripts/devrunner.js"

At this point all you run is yarn dev as per usual.

This script is tested on windows git bash but should work with mac just fine as well. This will catch an interrupt signal successfully and propogate that kill to the rest of the process tree from the original electron-webpack dev command.

b-zurg avatar Jan 24 '20 11:01 b-zurg

I'm not sure if this is related to this problem, or another problem, but whenever something goes wrong with the compile (an error or a warning -- since #305 has yet to be released) the electron process doesn't get launched until after I ctrl+c out of the dev runner. It never successfully launches however so I must force kill it (on OS X) which results in a leftover shell process (in my case zsh) using 100% of one core which I have to manually kill.

This problem does not happen if the electron process launches normally and I don't have to force quit it. Presumably because when I ctrl+c the dev runner it has closed by the time the electron process starts so it's orphaned.

UberMouse avatar Jan 27 '20 00:01 UberMouse

I have the same issue on Windows 10, [email protected], and [email protected].

When closing the app (launched in development mode), only the electron processes properly close.
Then the cli.js script hangs (blocking the terminal) for 10 seconds before stopping, orphaning the webpack dev server process, which stays alive, locking the port untill I manually kill it.

Here is the full command that launched the webpack dev server :

node   "C:\workspace\electron-webpack\node_modules\.bin\\..\webpack-dev-server\bin\webpack-dev-server.js" --color --env.autoClean=false --config C:\workspace\electron-webpack\node_modules\electron-webpack\webpack.renderer.config.js

Runnerw is not an issue here since I still have the issue without using it.

On a side note, I managed to make the process killing workaround work, but I really don't want to rely on that.

Seblor avatar Mar 03 '20 10:03 Seblor

I can confirm what @glek said.

Dropping the isWin conditionals in ChildProcessManager and using the simple way - spawn(program, args, options) and child.kill("SIGINT") - solves the issues and leads to a much improved performance and responsiveness. The processes are closed properly.

Not sure whether this can lead to other problems - I've read somewhere that child.kill on windows doesn't emit any signals/messages but just kills immediatly, not allowing listeners/observers to handle it,

@develar do you remember the motivation behind using runnerw.exe for launching and child.stdin!!.end(Buffer.from([5, 5])) for exiting? Dropping them would simplify the codebase in a nice way and properly kill the background processes at the right time. Seems like a win-win?

@loopmode Does this solution still work for you? If so, do you mind sharing some code if you still have it.

morecommits avatar Mar 02 '21 18:03 morecommits

Hi. I haven't worked with electron in a long time, but I guess it's still working. And I don't have actual code - all I did was hack the line inside the installed node_modules. But it's about line 7 of this source file: https://github.com/electron-userland/electron-webpack/blob/master/packages/electron-webpack/src/dev/ChildProcessManager.ts

loopmode avatar Mar 02 '21 18:03 loopmode