electron icon indicating copy to clipboard operation
electron copied to clipboard

[Bug]: Spawning and unreferencing a child process prevents electron from exiting

Open Josh-G opened this issue 3 years ago • 20 comments

Preflight Checklist

Electron Version

19.0.7

What operating system are you using?

Other Linux

Operating System Version

Debian 10 (buster)

What arch are you using?

arm64 (including Apple Silicon)

Last Known Working Electron version

No response

Expected Behavior

Running the following:

spawn('sleep', ['10'], {
    detached: true,
    stdio: 'ignore',
}).unref();

should allow Electron to exit without waiting for the child process.

Actual Behavior

Electron emits the correct events, however some electron processes linger until the child process has completed.

Testcase Gist URL

https://gist.github.com/Josh-G/aadee165b50c7629d5f1c9340728a8ca

Additional Information

I've also created a repo with a workflow that demonstrates the issue; https://github.com/Josh-G/electron-spawn-detached

I believe this may be the same as, or a regression of, https://github.com/electron/electron/issues/2208 https://github.com/electron/electron/issues/13870. I've reproduced this on Linux on arm64 + x64 with Debian and Ubuntu (thru GitHub Action).

Josh-G avatar Jul 01 '22 12:07 Josh-G

I've noticed this in the past as well. Some processes don't exit:

  28712 ?        S      0:00 /Electron Fiddle/electron-bin/19.0.7/electron --type=zygote --no-zygote-sandbox --enable-crashpad --enable-crashpad
  28713 ?        S      0:00 /Electron Fiddle/electron-bin/19.0.7/electron --type=zygote --enable-crashpad --enable-crashpad
  28715 ?        S      0:00 /Electron Fiddle/electron-bin/19.0.7/electron --type=zygote --enable-crashpad --enable-crashpad

while these exit immediately (if you wrap process.exit in a setTimeout you will see them go away while the above stay until sleep is done):

  28971 ?        Sl     0:00 /Electron Fiddle/electron-bin/19.0.7/electron --type=gpu-process --enable-crashpad --enable-crash-reporter=a9f51b37-898e-4b52-a491-88193519d896,no_channel --user-data-dir=/illustrious-speaker-spend-o4irg --gpu-preferences=WAAAAAAAAAAgAAAIAAAAAAAAAAAAAAAAAABgAAAAAAA4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAIAAAAAAAAAABAAAAAAAAAAgAAAAAAAAACAAAAAAAAAAIAAAAAAAAAA== --shared-files --field-trial-handle=0,i,10080314104194432827,127912701232379743,131072 --disable-features=SpareRendererForSitePerProcess
  28986 ?        Sl     0:00 /Electron Fiddle/electron-bin/19.0.7/electron --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --enable-crashpad --enable-crash-reporter=a9f51b37-898e-4b52-a491-88193519d896,no_channel --user-data-dir=/illustrious-speaker-spend-o4irg --shared-files=v8_context_snapshot_data:100 --field-trial-handle=0,i,10080314104194432827,127912701232379743,131072 --disable-features=SpareRendererForSitePerProcess --enable-crashpad

Prinzhorn avatar Jul 01 '22 17:07 Prinzhorn

Well, I just had a deja vu and I commented the exact same thing a year ago :smile: https://github.com/electron/electron/issues/24520#issuecomment-874941656

Electron processes are kept alive

For some reason this child process (that now belongs to systemd) keeps several Electron processes alive. To me this looks broken?

 $ ps ax | grep electron
  16478 ?        S      0:00 /home/alex/.config/Electron Fiddle/electron-bin/13.1.6/electron --type=zygote --no-zygote-sandbox
  16479 ?        S      0:00 /home/alex/.config/Electron Fiddle/electron-bin/13.1.6/electron --type=zygote
  16481 ?        S      0:00 /home/alex/.config/Electron Fiddle/electron-bin/13.1.6/electron --type=zygote

Back then what I meant with "normal unix behavior" is that the sleep process will be moved to the next parent (e.g. systemd) and does not exit with Electron. But it shouldn't keep Electron waiting for it.

Prinzhorn avatar Jul 01 '22 17:07 Prinzhorn

When using electron-updater on Linux with the AppImage target, this can cause a significant amount of lingering processes on long-running hosts that apply multiple updates

Josh-G avatar Jul 03 '22 18:07 Josh-G

Just started writing e2e tests and now this becomes a real problem. The tests will time out because Electron never exits.

Even this is not enough:

app.exit(0);
process.exit(0);

As long as the child process does not exit, playwrights await app.close() will never resolve. If I kill the child process manually, the test passes, because the lingering Electron processes can finally exit.

Prinzhorn avatar Jul 29 '22 08:07 Prinzhorn

I've tried electron 20-x-y and the 21 alpha, just in case there was any change, without success.

Josh-G avatar Aug 05 '22 14:08 Josh-G

I am seeing the exact same behavior, I have a work around I'm using right now...

Basically I created a function that calls the "app.close/process.exit" message, but ALSO kills all processes associated with the parent if a forceExit flag is set and it is on linux. Not the most graceful solution, but the only one I could find that actually worked... So forceExit gets set true in a couple instances in my app while the child is still running...

export function exitApp(value=0, forceExit=false) {
  if (forceExit) {
    if (process.platform === 'linux') {
      // TODO: Remove HACK -- This is because of Electron Bug only on Linux and spawns
      const result = execSync('ps -o pgid= -p ' + process.pid);
      const val = parseInt(result.toString().trim(), 10);
      // If we don't have a Group ID, there is nothing we can do, this means "ps" isn't installed... 
      if (val > 0) {
        spawn('kill', ['-term', '--', '-' + val], {detached: true, stdio: 'ignore'});
        app.quit();
        process.exit(0);
      } 
    }
  }
  app.quit();
  process.exit(value);
}

NathanaelA avatar Aug 05 '22 18:08 NathanaelA

The issue is that Chrome/Electron leaks open file-descriptors into the child-process. For one reason or another, these open file-descriptors being held by the child-process are keeping parts of Electron from exiting until they are closed. Try looking at the /proc/$PID/fd filesystem for the child-process, and you will see all of the inherited open descriptors. The general problem was discussed here, and is in a wont-fix status: https://github.com/electron/electron/issues/1447

One way around this is to loop over all the open file-descriptors that your child-process has inherited and close them all. (of course it would be better if Electron were to provide this functionality in the child_process functions directly...)

Below is a wrapper which accomplishes this with some bash magic:

const mySpawn = (command, args = [], options) => spawn(
  '/bin/bash',
  ['-c', 'for fd in $(ls /proc/$$/fd); do case "$fd" in 0|1|2|255) ;; *) eval "exec $fd<&-" ;; esac ; done; exec "$@"' , '--', command, ...args],
  options
);

// This now works...
mySpawn('sleep', ['10'], {
    detached: true,
    stdio: 'ignore',
}).unref();

p120ph37 avatar Oct 12 '22 03:10 p120ph37

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the latest version of Electron or in the beta—please include it with your comment!

github-actions[bot] avatar Jan 11 '23 02:01 github-actions[bot]

Still repros with 22.0.1 and 23.0.0-beta.1. After the main process exits, these three processes will stay until the child has exited:

/node_modules/electron/dist/electron --type=zygote --no-zygote-sandbox
/node_modules/electron/dist/electron --type=zygote
/node_modules/electron/dist/electron --type=zygote

Prinzhorn avatar Jan 11 '23 10:01 Prinzhorn

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the latest version of Electron or in the beta—please include it with your comment!

github-actions[bot] avatar Apr 13 '23 01:04 github-actions[bot]

This issue still affects the latest Electron, I'm now using the workaround here https://github.com/electron/electron/issues/34808#issuecomment-1275530924 by p120ph37

NathanaelA avatar Apr 13 '23 02:04 NathanaelA

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the latest version of Electron or in the beta—please include it with your comment!

github-actions[bot] avatar Jul 13 '23 02:07 github-actions[bot]

Anyway we can turn off the "Stale" bot on this issue?

This issue still affects the latest Electron, I'm still using the workaround here https://github.com/electron/electron/issues/34808#issuecomment-1275530924 by p120ph37

NathanaelA avatar Jul 13 '23 02:07 NathanaelA

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the latest version of Electron or in the beta—please include it with your comment!

Anyway we can turn off the "Stale" bot on this issue?

This issue still affects the latest Electron, I'm still using the workaround here https://github.com/electron/electron/issues/34808#issuecomment-1275530924 by p120ph37

NathanaelA avatar Oct 13 '23 02:10 NathanaelA

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the latest version of Electron or in the beta—please include it with your comment!

Anyway we can turn off the "Stale" bot on this issue?

This issue still affects the latest Electron, I'm still using the workaround here https://github.com/electron/electron/issues/34808#issuecomment-1275530924 by p120ph37

NathanaelA avatar Jan 12 '24 16:01 NathanaelA

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. If you have any new additional information—in particular, if this is still reproducible in the latest version of Electron or in the beta—please include it with your comment!

Anyway we can turn off the "Stale" bot on this issue?

This issue still affects the latest Electron, I'm still using the workaround here https://github.com/electron/electron/issues/34808#issuecomment-1275530924 by p120ph37

NathanaelA avatar Apr 13 '24 03:04 NathanaelA

I received the following similar error "white screen" when running element-desktop --enable-logging on a Nvidia GPU GTX 1080. All this :hankey: javascript; no one seems to know how to code with C++ anymore :cry: .

I build my applications with GTK 4 (C/C++) in parallel with a nice UI named Cambalache.

Electron Version: electron29-29.3.1-1 Operating System: Arch Linux

So many npm/nodejs monsters nowadays.

Anyone have any recommendations for a client built with non-js :hankey: ? JS is a security nightmare to begin with and am humored by all the js being used for secure messaging app..electron is a bloated piece of yuk imo and should rarely be used for a professional application.

A fresh init of element-desktop with electron-29 :hankey:

Resetting the UI components after locale change
Resetting the UI components after locale change
[33791:0421/192133.432115:ERROR:angle_platform_impl.cc(44)] Display.cpp:1052 (initialize): ANGLE Display::initialize error 12289: Could not create a backing OpenGL context.
ERR: Display.cpp:1052 (initialize): ANGLE Display::initialize error 12289: Could not create a backing OpenGL context.
[33791:0421/192133.432323:ERROR:gl_display.cc(515)] EGL Driver message (Critical) eglInitialize: Could not create a backing OpenGL context.
[33791:0421/192133.432408:ERROR:gl_display.cc(786)] eglInitialize OpenGL failed with error EGL_NOT_INITIALIZED, trying next display type
[33791:0421/192133.515433:ERROR:angle_platform_impl.cc(44)] Display.cpp:1052 (initialize): ANGLE Display::initialize error 12289: Could not create a backing OpenGL context.
ERR: Display.cpp:1052 (initialize): ANGLE Display::initialize error 12289: Could not create a backing OpenGL context.
[33791:0421/192133.515593:ERROR:gl_display.cc(515)] EGL Driver message (Critical) eglInitialize: Could not create a backing OpenGL context.
[33791:0421/192133.515668:ERROR:gl_display.cc(786)] eglInitialize OpenGLES failed with error EGL_NOT_INITIALIZED
[33791:0421/192133.515745:ERROR:gl_display.cc(820)] Initialization of all EGL display types failed.
[33791:0421/192133.515818:ERROR:gl_ozone_egl.cc(26)] GLDisplayEGL::Initialize failed.
[33791:0421/192133.939565:ERROR:angle_platform_impl.cc(44)] Display.cpp:1052 (initialize): ANGLE Display::initialize error 12289: Could not create a backing OpenGL context.
ERR: Display.cpp:1052 (initialize): ANGLE Display::initialize error 12289: Could not create a backing OpenGL context.
[33791:0421/192133.939728:ERROR:gl_display.cc(515)] EGL Driver message (Critical) eglInitialize: Could not create a backing OpenGL context.
[33791:0421/192133.939850:ERROR:gl_display.cc(786)] eglInitialize OpenGL failed with error EGL_NOT_INITIALIZED, trying next display type
[33791:0421/192134.024441:ERROR:angle_platform_impl.cc(44)] Display.cpp:1052 (initialize): ANGLE Display::initialize error 12289: Could not create a backing OpenGL context.
ERR: Display.cpp:1052 (initialize): ANGLE Display::initialize error 12289: Could not create a backing OpenGL context.
[33791:0421/192134.024588:ERROR:gl_display.cc(515)] EGL Driver message (Critical) eglInitialize: Could not create a backing OpenGL context.
[33791:0421/192134.024665:ERROR:gl_display.cc(786)] eglInitialize OpenGLES failed with error EGL_NOT_INITIALIZED
[33791:0421/192134.024737:ERROR:gl_display.cc(820)] Initialization of all EGL display types failed.
[33791:0421/192134.024805:ERROR:gl_ozone_egl.cc(26)] GLDisplayEGL::Initialize failed.
[33791:0421/192134.027053:ERROR:viz_main_impl.cc(196)] Exiting GPU process due to errors during initialization
[33827:0421/192134.201826:WARNING:vaapi_wrapper.cc(1497)] Skipping nVidia device named: nvidia-drm
[33827:0421/192134.206091:WARNING:sandbox_linux.cc(418)] InitializeSandbox() called with multiple threads in process gpu-process.
[33811:0421/192134.214034:ERROR:command_buffer_proxy_impl.cc(131)] ContextResult::kTransientFailure: Failed to send GpuControl.CreateCommandBuffer.
<--- Last few GCs --->

[4:0x30a424a38000]      725 ms: Mark-Compact (reduce) 45.5 (63.5) -> 45.4 (48.2) MB, pooled: 0 MB, 91.32 / 0.00 ms  (average mu = 0.874, current mu = 0.874) last resort; GC in old space requested
[4:0x30a424a38000]      809 ms: Mark-Compact (reduce) 45.4 (48.2) -> 45.4 (48.2) MB, pooled: 0 MB, 83.64 / 0.00 ms  (average mu = 0.784, current mu = 0.000) last resort; GC in old space requested


<--- JS stacktrace --->

[33083:0421/191751.181926:ERROR:v8_initializer.cc(799)] V8 javascript OOM (Committing semi space failed.).
Renderer process crashed - see https://www.electronjs.org/docs/tutorial/application-debugging for potential debugging information.

^CError sending from webFrameMain:  Error: Render frame was disposed before WebFrameMain could be accessed
    at s.send (node:electron/js2c/browser_init:2:84285)
    at _.send (node:electron/js2c/browser_init:2:69269)
    at App.beforeQuit (/usr/lib/element/app.asar/lib/electron-main.js:551:82)
    at App.emit (node:events:514:28)
    at App.emit (node:domain:488:12)
Segmentation fault (core dumped)

oDinZu avatar Apr 21 '24 22:04 oDinZu