Skip to content
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

Using worker_threads that keep running indefinitely fails assertion on SIGTERM #23315

Closed
KishanBagaria opened this issue Apr 28, 2020 · 28 comments

Comments

@KishanBagaria
Copy link
Contributor

KishanBagaria commented Apr 28, 2020

Issue Details

  • Electron Version:
    • v9.0.0-beta.21 and 8.2.4
  • Operating System:
    • macOS 10.15.4

Actual Behavior

An electron app that uses a worker thread that runs indefinitely in the main process (because of a server listening on a port etc.) throws the following error on exit:

/Users/kishan/Downloads/electron-test/node_modules/electron/dist/Electron.app/Contents/MacOS/Electron[93383]: ../../third_party/electron_node/src/node_worker.cc:358:virtual node::worker::Worker::~Worker(): Assertion `stopped_' failed.
 1: 0x10f4ce9b5 node::Buffer::New(v8::Isolate*, char*, unsigned long, void (*)(char*, void*), void*) [/Users/kishan/Downloads/electron-test/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
 2: 0x10f4ce73f node::Buffer::New(v8::Isolate*, char*, unsigned long, void (*)(char*, void*), void*) [/Users/kishan/Downloads/electron-test/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
 3: 0x10f54eb01 node::MultiIsolatePlatform::CancelPendingDelayedTasks(v8::Isolate*) [/Users/kishan/Downloads/electron-test/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
 4: 0x10f54eb3e node::MultiIsolatePlatform::CancelPendingDelayedTasks(v8::Isolate*) [/Users/kishan/Downloads/electron-test/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
 5: 0x10f47f56f node::EmitAsyncDestroy(node::Environment*, node::async_context) [/Users/kishan/Downloads/electron-test/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
 6: 0x10f44cc4e node::FreeEnvironment(node::Environment*) [/Users/kishan/Downloads/electron-test/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
 7: 0x1095c4c81 ElectronInitializeICUandStartNode [/Users/kishan/Downloads/electron-test/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
 8: 0x10b0fac71 v8::internal::SetupIsolateDelegate::SetupHeap(v8::internal::Heap*) [/Users/kishan/Downloads/electron-test/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
 9: 0x10b0fc514 v8::internal::SetupIsolateDelegate::SetupHeap(v8::internal::Heap*) [/Users/kishan/Downloads/electron-test/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
10: 0x10b0f8294 v8::internal::SetupIsolateDelegate::SetupHeap(v8::internal::Heap*) [/Users/kishan/Downloads/electron-test/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
11: 0x10afa1616 v8::internal::SetupIsolateDelegate::SetupHeap(v8::internal::Heap*) [/Users/kishan/Downloads/electron-test/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
12: 0x10afa126b v8::internal::SetupIsolateDelegate::SetupHeap(v8::internal::Heap*) [/Users/kishan/Downloads/electron-test/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
13: 0x10d522488 v8::internal::SetupIsolateDelegate::SetupHeap(v8::internal::Heap*) [/Users/kishan/Downloads/electron-test/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
14: 0x10a2222b4 ElectronInitializeICUandStartNode [/Users/kishan/Downloads/electron-test/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
15: 0x1094f8a54 ElectronMain [/Users/kishan/Downloads/electron-test/node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework]
16: 0x108377110  [/Users/kishan/Downloads/electron-test/node_modules/electron/dist/Electron.app/Contents/MacOS/Electron]
17: 0x7fff6cb41cc9 start [/usr/lib/system/libdyld.dylib]

Expected Behavior

It shouldn't throw the error.

To Reproduce

Couldn't repro this in Electron Fiddle but the following should work:

  1. Copy the following to worker-exit-issue.js
const { Worker, isMainThread } = require('worker_threads')

if (isMainThread) {
  new Worker(__filename)
  console.log('main thread')
} else {
  console.log('worker')
  const http = require('http')
  const server = http.createServer((req, res) => {
    res.end()
  })
  server.listen(12345)
}
  1. Run electron worker-exit-issue.js

  2. Quit the Electron app that runs from Dock or equivalent. (CTRL+C/SIGINT will not throw the error)

  3. You'll see the above error printed in the console:

This doesn't happen if I run node worker-exit-issue.js

@KishanBagaria KishanBagaria changed the title Using worker_threads that keep running fails assertion on SIGTERM Using worker_threads that keep running indefinitely fails assertion on SIGTERM Apr 28, 2020
@codebytere
Copy link
Member

codebytere commented Apr 28, 2020

@KishanBagaria There is some existing incompatibility with worker_threads in Node.js at the moment that's existed for a while - we're looking into it but recommend you try to use Web Workers instead where possible :)

@KishanBagaria
Copy link
Contributor Author

I would but I need to use native modules. I also have to move my node-mac-contacts code to a worker thread from the renderer process since it's compute heavy :)

@flotwig
Copy link
Contributor

flotwig commented May 29, 2020

@KishanBagaria I believe I'm having the same issue: #23366

@KishanBagaria
Copy link
Contributor Author

Is there a way I can silence this by monkey patching or something?

@flotwig
Copy link
Contributor

flotwig commented Jul 27, 2020

@KishanBagaria we are working around it by monkey-patching process.exit to exit all worker_threads before calling process.exit. This is a dirty hack because (among other reasons) it makes process.exit an asynchronous operation, but I've not been able to find a better workaround :/

You will have to audit all usages of process.exit in your codebase and ensure that they all handle an asynchronous process.exit correctly. Additionally, your process can no longer exit normally when there are no queued events, you'll always have to make sure you call the worker exit routine before exiting.

Initially, we were calling .terminate() on each worker_thread on process.exit and waiting for that to finish, but some users were still running into problems with SIGABRT. So we switched to using postMessage to tell each thread to kill itself, waiting for that, and then exiting the parent process. This seems to work fine in practice: https://github.com/cypress-io/cypress/pull/7572/files

Still, this is a bad workaround due to the reasons mentioned above. I hope someone from the Electron team can take an in-depth look at this issue.

@dpaola2
Copy link

dpaola2 commented Aug 28, 2020

I'm this boat as well - while trying to refactor some blocking native logic out of the main thread for performance reasons, I'm now encountering an app crash every time I exit the app because I followed the advice in https://www.electronjs.org/docs/tutorial/performance and used Node.js workers.

From where I'm sitting, it looks to me like there is no way to have multithreaded native logic without encountering this error. Is that accurate?

@linonetwo
Copy link

No way around, my code is waiting enough of time to prevent race condition:

async function stopWorker(id) {
  const worker = wikiWorkers[id];
  if (!worker) {
    logger.warning(
      `No worker for ${id}. No running worker, means maybe worker failed to start`
    );
    return Promise.resolve();
  }
  return (
    new Promise(resolve => {
      worker.postMessage({ type: 'command', message: 'exit' });
      worker.once('exit', resolve);
      worker.once('error', resolve);
    })
      .timeout(100)
      .catch(error => {
        logger.info(`Wiki-worker have error ${error} when try to stop`); // this never happens
        return worker.terminate();
      })
      .then(() => {
        delete wikiWorkers[id]; // this is useless, but I tried
        logger.info(`Wiki-worker for ${id} stopped`);
      })
  );
}

  const tasks = [];
  for (const id of Object.keys(workers)) {
    tasks.push(stopWiki(id));
  }
  await Promise.all(tasks);
  await Promise.delay(5000);

And in worker

if (!isMainThread) {
  startNodeJSWiki();
  parentPort.once('message', async message => {
    if (typeof message === 'object' && message.type === 'command' && message.message === 'exit') {
      process.exit(0);
    }
  });
}

and in electron

  app.on('before-quit', async event => {
    logger.info('Quitting worker threads and watcher.');
    await Promise.all([stopAllWiki(), stopWatchAllWiki()]);
    logger.info('Worker threads and watchers all terminated.');
    logger.info('Quitting I18N server.');
    clearMainBindings(ipcMain);
    logger.info('Quitted I18N server.');

    // https://github.com/atom/electron/issues/444#issuecomment-76492576
    // if (process.platform === 'darwin') {
    //   const win = mainWindow.get();
    //   if (win) {
    //     logger.info('App force quit on MacOS');
    //     win.forceClose = true;
    //   }
    // }
    app.exit(0);
  });

  app.on('quit', async () => {
    logger.info('App quit');
  });

All of this are not working. Always

Electron.app/Contents/MacOS/Electron exited with signal SIGSEGV
[1] wait-on http://localhost:3000 && electron . exited with code 1
--> Sending SIGTERM to other processes..
[0] cross-env BROWSER=none npm run start exited with code 1

linonetwo added a commit to tiddly-gittly/TidGi-Desktop that referenced this issue Oct 11, 2020
@linonetwo
Copy link

I tried @flotwig 's solution, seems it is not working.

@codebytere
Copy link
Member

codebytere commented Oct 13, 2020

This issue seems like it's present in Node.js v12 but not v14 - i can't repro it after #25249 but can in versions prior

@linonetwo
Copy link

@codebytere that is in electron v11 ? I will try that later

@regular
Copy link

regular commented Oct 22, 2020

Tried with Electron 11.0.0-beta13. It crashes even when all threads terminate prior to calling app.quit(), like described in #26103 it's enough to have had a thread running at any point to make Electron crash on exit.

@codebytere
Copy link
Member

I'm fairly certain it's this commit: nodejs/node@b6738bc

that would need to be backported to 9-x-y through 11-x-y

@linonetwo
Copy link

I can confirm this is fixed in v12 nightly, but v12 drop support for non-NAPI native addons, so I have to disable asar to use those native packages.
But, yes, v12 fixes this already.

@KishanBagaria
Copy link
Contributor Author

KishanBagaria commented Nov 10, 2020

Would be great to have this backported! 🎉

For us, Sentry is getting a lot of bad crash dumps because of this.

@m4heshd
Copy link

m4heshd commented Feb 20, 2021

Having the same issue. Blocked from everywhere. Can't use web workers because of the need to use native modules and it can't seem to load any kind of external module. Can't use worker threads because of this issue. So frustrated not being able to move forward.
@flotwig Even if you end all the threads gracefully, Electron will exit with code -1073741819 (0xC0000005) whenever the process has been ended. An access violation on Windows.

@indutny-signal
Copy link
Contributor

A different stack trace for the same issue with a testing build of Electron:

  * frame #0: 0x0000000122464f80 Electron Framework`::AddIsolateFinishedCallback() [inlined] operator bool at memory:3851:68 [opt]
    frame #1: 0x0000000122464f74 Electron Framework`::AddIsolateFinishedCallback() at node_platform.cc:354 [opt]
    frame #2: 0x000000012222686e Electron Framework`::AddArrayBufferAllocatorToKeepAliveUntilIsolateDispose() at env.cc:1074:15 [opt]
    frame #3: 0x000000012255e5fb Electron Framework`::CleanupHook() at sharedarraybuffer_metadata.cc:75:18 [opt]
    frame #4: 0x00000001222193af Electron Framework`::RunCleanup() at env.cc:627:7 [opt]
    frame #5: 0x000000012212d20e Electron Framework`::FreeEnvironment() at environment.cc:335:8 [opt]
    frame #6: 0x0000000100717d88 Electron Framework`::PostMainMessageLoopRun() [inlined] operator() at memory:2378:5 [opt]
    frame #7: 0x0000000100717d80 Electron Framework`::PostMainMessageLoopRun() [inlined] reset at memory:2633 [opt]
    frame #8: 0x0000000100717d66 Electron Framework`::PostMainMessageLoopRun() at electron_browser_main_parts.cc:598 [opt]
    frame #9: 0x000000010b68dced Electron Framework`::ShutdownThreadsAndCleanUp() at browser_main_loop.cc:1057:13 [opt]
    frame #10: 0x000000010b693ea4 Electron Framework`::Shutdown() at browser_main_runner_impl.cc:178:17 [opt]
    frame #11: 0x000000010b684796 Electron Framework`::BrowserMain() at browser_main.cc:49:16 [opt]
    frame #12: 0x000000010b059d75 Electron Framework`::RunServiceManager() [inlined] RunBrowserProcessMain at content_main_runner_impl.cc:507:10 [opt]
    frame #13: 0x000000010b059cb4 Electron Framework`::RunServiceManager() at content_main_runner_impl.cc:979 [opt]
    frame #14: 0x000000010b058f28 Electron Framework`::Run() at content_main_runner_impl.cc:858:12 [opt]
    frame #15: 0x0000000105e07384 Electron Framework`::RunContentProcess() at content_main.cc:373:36 [opt]
    frame #16: 0x0000000105e07a78 Electron Framework`::ContentMain() at content_main.cc:399:10 [opt]
    frame #17: 0x00000001003ca00d Electron Framework`ElectronMain at electron_library_main.mm:23:10 [opt]
    frame #18: 0x0000000100004acd Electron`main at electron_main.cc:274:10 [opt]
    frame #19: 0x00007fff2057c621 libdyld.dylib`start + 1

@linonetwo
Copy link

@indutny-signal I think upgrade to v12 beta solves this.

@m4heshd
Copy link

m4heshd commented Mar 31, 2021

@linonetwo Why beta? The stable version was released a long time ago. And yeah it's fixed because of Node ABI v83.

@indutny-signal
Copy link
Contributor

It still isn't fixed in the latest v11 release which was published a week ago.

@m4heshd
Copy link

m4heshd commented Mar 31, 2021

@indutny-signal You're never gonna get a fix on v11 because it's using older Node ABI (v72). That will never change. (As far as I know according to the information)

@indutny
Copy link
Contributor

indutny commented Mar 31, 2021

@m4heshd of course it can be fixed. Just need to fix node v12 first 😂 (See: nodejs/node#38010)

@m4heshd
Copy link

m4heshd commented Mar 31, 2021

@indutny big props. Now I'm glad I added that last part on my comment 😂. Wasted countless amounts of hours because of this. Hope It'll get merged soon. But still, not sure about the Electron side of it. Unless you integrate that too.

@indutny-signal
Copy link
Contributor

@m4heshd I don't anticipate any problems with the electron release, since it'd be just a version bump for node that they use. That being said only time will show if I was right!

@m4heshd
Copy link

m4heshd commented Mar 31, 2021

@indutny Agreed. Well, hoping for the best. 🤞🏼 (Still wondering why devs on Electron guaranteed that It's unfixable though 🥴)

addaleax added a commit to addaleax/electron that referenced this issue Mar 31, 2021
The Environment is created after the Isolate and its platform data,
so it also needs to be torn down before it. This fixes the crash
mentioned below.

(Thanks to Fedor Indutny for debugging this!)

Fixes: electron#23315
@indutny
Copy link
Contributor

indutny commented Mar 31, 2021

Correction, the proper fix actually needs to be done in electron: #28468 Thanks @addaleax for helping me with this!

@indutny-signal
Copy link
Contributor

@m4heshd does this release fix the problem for you?

@m4heshd
Copy link

m4heshd commented Apr 7, 2021

@m4heshd does this release fix the problem for you?

Well you've apparently done the impossible. 😁 But I migrated all of my projects to v12 as soon as I discovered this issue. Still, thank you because It's gonna benefit a lot of devs. slowclaps 👏🏽

@nornagon
Copy link
Member

nornagon commented Apr 9, 2021

Sounds like this is fixed, so I'll close the issue. Let me know if I'm mistaken and I can reopen.

@nornagon nornagon closed this as completed Apr 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.