node-addon-api icon indicating copy to clipboard operation
node-addon-api copied to clipboard

`ThreadSafeFunction` should handle exceptions in async callbacks identical to Node itself

Open mmomtchev opened this issue 3 years ago • 14 comments

This is a duplicate of #669

When a JS callback called from a ThreadSafeFunction throws an exception, the result is:

terminate called after throwing an instance of 'Napi::Error'
  what():  unexpected error
Aborted (core dumped)

While this:

setImmediate(() => {
  throw new Error('unexpected error');
});

ends up like this:

/home/mmom/src/exprtk.js/uncaught.js:2
    throw new Error('err');
    ^

Error: err
    at Immediate.<anonymous> (/home/mmom/src/exprtk.js/uncaught.js:2:9)
    at processImmediate (internal/timers.js:464:21)

Why is it such a big deal? Because, as a module author, the first one will surely end up in an issue for my module, while with the second one, the user will correctly recognize what is happening.

Ideally, there should be a way to call Node's internal method which terminates the process.

mmomtchev avatar Jan 02 '22 12:01 mmomtchev

This issue is stale because it has been open many days with no activity. It will be closed soon unless the stale label is removed or a comment is made.

github-actions[bot] avatar Apr 03 '22 00:04 github-actions[bot]

I believe this is addressed by the core pr: https://github.com/nodejs/node/pull/36510

KevinEady avatar May 03 '22 08:05 KevinEady

Discussed in the node-api team meeting and agreed it should be resolved by #36510

mhdawson avatar May 06 '22 15:05 mhdawson

@mmomtchev can you check that #36510 which has landed in the primary branch resolved the issue for you

mhdawson avatar Jun 03 '22 15:06 mhdawson

@mhdawson This is a problem because after #36510 the only possible fix is to leave the exception handling in node-addon-api::Function::MakeCallback to Node itself - which means that without it exceptions will be silently ignored. This means that node-addon-api will have to detect if this PR is there or not - especially since its exception handling runs after node-addon-api::Function::MakeCallback

mmomtchev avatar Jun 04 '22 10:06 mmomtchev

In fact, I think that the fundamental problem is that #36510 is an API-breaking PR that requires a NAPI_VERSION bump - before this PR napi_make_callback left the exception handling to the user while now it handles it itself. I also wonder if there is (if there is, I can't see it) a way to for a module to force the ignoring of this exception. node-addon-api should use this method to force the ignoring of the exception on newer Node.js versions and then handle it itself - like it used to do on previous versions.

mmomtchev avatar Jun 04 '22 11:06 mmomtchev

@mmomtchev right now the new behavior should be off by default see - https://github.com/nodejs/node/pull/36510#issuecomment-1050231172. Is that not the case?

We should be able to check the flag in node-api (I think) and use that to choose how to handle the exception.

It's possible we still need a chagne on the node-addon-api side to do this though. (ie if flag is set to do the right thing)

Am I missing something?

mhdawson avatar Jun 13 '22 20:06 mhdawson

If you can check for this flag while remaining backwards compatible, sure, this can be a solution.

Still, it will be somewhat problematic for the end user (the module author) - is it up to him to check for raised exceptions or not - as there will be two possibilities within the same version number. But since it is possible to easily handle both, it might stay like this. Currently a module that calls a ThreadSafeFunction must check for exceptions to not trigger the abort() which looks as a crash to the end user (the module user): https://github.com/mmomtchev/exprtk.js/blob/dbeb2d14e793e160ebac91355972330d9ed5b95a/src/async.h#L240

mmomtchev avatar Jun 13 '22 20:06 mmomtchev

This issue is stale because it has been open many days with no activity. It will be closed soon unless the stale label is removed or a comment is made.

github-actions[bot] avatar Sep 12 '22 00:09 github-actions[bot]

Next steps:

  • try running reproducer with the command line flag added to core. Validate that it fixes the issue
  • if fixed by runtime command line flag, look at introducing a feature flag that allows it to be turned on

mhdawson avatar Sep 23 '22 15:09 mhdawson

@legendecas will look at:

try running reproducer with the command line flag added to core. Validate that it fixes the issue

mhdawson avatar Sep 23 '22 15:09 mhdawson

I believe https://github.com/nodejs/node/pull/36510 can handle the uncaught exceptions in async callbacks. However, as the flag requires the user to explicitly opt-in, the solution might not be optimal for library authors.

Library authors now can still emit an uncaughtException with https://nodejs.org/api/n-api.html#napi_fatal_exception. This can help library authors to migrate to the behavior enforced in https://github.com/nodejs/node/pull/36510.

As a follow-up, we'll investigate how to help add-ons to migrate to expected runtime behavior, without any breakages, like the flags that are being worked at https://github.com/nodejs/node/pull/42557#discussion_r995559115.

legendecas avatar Oct 17 '22 08:10 legendecas

This issue is stale because it has been open many days with no activity. It will be closed soon unless the stale label is removed or a comment is made.

github-actions[bot] avatar Jan 16 '23 00:01 github-actions[bot]

This issue is stale because it has been open many days with no activity. It will be closed soon unless the stale label is removed or a comment is made.

github-actions[bot] avatar Apr 28 '23 00:04 github-actions[bot]