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

When to use NODE_API_ADDON() instead of NODE_API_MODULE()?

Open mkaivs opened this issue 2 years ago • 3 comments

From the napi-inl.h header file:

  • NODE_API_MODULE() registers an add-on based on an initializer function.

  • NODE_API_ADDON() registers add-on based on a subclass of Addon<T>.

The examples in node-addon-examples all use NODE_API_MODULE() so when should I use NODE_API_ADDON() instead of NODE_API_MODULE()? In other words, what are the benefits subclassing Addon<T> provides over an initializer function?

mkaivs avatar Jun 16 '22 18:06 mkaivs

Hi @mkaivs, you should use the NODE_API_ADDON() or NODE_API_NAMED_ADDON() with an add-on based on a subclass of Addon<T> when you want to load the add-on in to multiple Node.js thread maybe multiple times. In this particular case all data that add-on hold should be associated with the right environment of execution. It's not safe store the global data in static variable.

I think that this is well documented here: https://github.com/nodejs/node-addon-api/blob/main/doc/addon.md

Creating add-ons that work correctly when loaded multiple times from the same source package into multiple Node.js threads and/or multiple times into the same Node.js thread requires that all global data they hold be associated with the environment in which they run. It is not safe to store global data in static variables because doing so does not take into account the fact that an add-on may be loaded into multiple threads nor that an add-on may be loaded multiple times into a single thread.

In case you need more informations please let me know I will try to help you.

NickNaso avatar Jun 16 '22 18:06 NickNaso

Hi @NickNaso,

Thank you for the explanation, so for example, if I have an initializer function as follow:

static int dummy_global = 0;

Napi::Object example::Init(Napi::Env env, Napi::Object exports) 
{
  
  g_message("Addon loaded in PID=%d, TGID=%ld (main-thread: %d) (dummy_global address: %p)",
  getpid(), 
  syscall(__NR_gettid), 
  getpid() == syscall(__NR_gettid), 
  (void*)&dummy_global);

// [...]
}

After my app start up, these statements are printed to the terminal:

** Addon loaded in PID=15147, TGID=15147 (main-thread: 1) (dummy_global address: 0x7f99ad6d31d8)
** Addon loaded in PID=15140, TGID=15140 (main-thread: 1) (dummy_global address: 0x7fad12a681d8)
** Addon loaded in PID=15147, TGID=15214 (main-thread: 0) (dummy_global address: 0x7f99ad6d31d8)
** Addon loaded in PID=15147, TGID=15216 (main-thread: 0) (dummy_global address: 0x7f99ad6d31d8)
** Addon loaded in PID=15147, TGID=15215 (main-thread: 0) (dummy_global address: 0x7f99ad6d31d8)
** Addon loaded in PID=15140, TGID=15221 (main-thread: 0) (dummy_global address: 0x7fad12a681d8)
** Addon loaded in PID=15140, TGID=15222 (main-thread: 0) (dummy_global address: 0x7fad12a681d8)
** Addon loaded in PID=15120, TGID=15120 (main-thread: 1) (dummy_global address: 0x7fbecd1541d8)

So here, there are 3 instances of the addons (3 different addresses for the dummy_global variable), worker threads shared the addon instance created by their parent process.

If I were to use a subclass of Addon<T>, instead of 3 addon instances, there will be 8 addon instances, one per each time the addon is loaded?

mkaivs avatar Jun 16 '22 21:06 mkaivs

@mkaivs with the example being added do you have any additional questions or is it ok to close out this issue?

mhdawson avatar Aug 05 '22 15:08 mhdawson

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 Nov 04 '22 00:11 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 Feb 03 '23 00:02 github-actions[bot]

Since this issue has no work done since Nov 2022, we are closing this issue. If you need more help, please reopen or create a new issue. Thanks!

KevinEady avatar Mar 10 '23 16:03 KevinEady