Skip to content

Important change of behaviour starting with Node.js v26.4.0 impacting async work in native modules #1756

Description

@mmomtchev

Starting from Node.js v26.4.0 native modules are expected to call the micro tasks queue and process.nextTick handlers themselves if they do any async work.

Node.js exports a RAII guard, CallbackScope, that does automatically at the end of the functions that create it.

The module is supposed to be doing this on the main thread after the async work has been completed.

Or, alternatively, there is the makeCallback method which combines a CallbackScope with a Call method - it is a shorthand for calling into JavaScript and running the micro tasks.

It appears that this has been specified to work this way since Node.js v9.0.0 but until now Node.js would always process the handlers in all cases. Starting with Node.js v26.4.0, this is no longer the case.

I have first encountered the problem with NAN and I haven't reproduced it with node-addon-api, but I see that this fully applies to it too.

Note that Node.js still calls the micro tasks most of the time except in some cases, which makes debugging this problem rather unpleasant.

  • The default OnOK``AsyncWorker uses Call instead of makeCallback
  • There is an AsyncResource class but this class is not used at all by AsyncWorker - it is up to the module to create it
  • This is also true when using the Promise helpers - they do not call the micro tasks either

Unlike NAN, node-addon-api exports all necessary APIs, however it is currently somewhat misleading and definitely does not make it clear that this is something that is up to the module (especially since until Node.js v26.4.0 it was not).

I think that by default the AsyncWorker class should create an AsyncContext that must be accessible to derived classes (protected) and the OnOK/OnError methods should use makeCallback with this async context. When using a Promise - or when overriding OnOK/OnError, there should be a mention in the documentation that the module must use a CallbackScope.

Further info:
nodejs/nan#1024
nodejs/node#66158

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions