Skip to content

How to have a background thread call back to JS multiple times? #438

Closed

Description

@twoi

TL;DR How can a long-running thread call a JS function repeatedly, i.e. without the use of AsyncWorker?

AsyncWorker seems to be for one long-running task that calls back to JS land only once, once finished.

In my scenario, a background thread is repeatedly calling back to JS land, something like relaying events that occur in native land to a JS callback. In the past (node.js 0.8), I did this with libuv's uv_async_send(), but I need to upgrade, and since uv and v8 have changed so much I thought I'd migrate straight over to node-addon-api, as it seems to have everything I need.

However I cannot seem to find out how to pull this off with AsyncContext and CallbackScope, which are made for cases like this, if I parse the docs correctly. However, all examples in the documentation and the tests in https://github.com/nodejs/node-addon-api/blob/master/test/ for both classes are (ironically?) working synchronously, and my attempts to migrate their callbacks over to run on a different thread have failed so far.

A nudge in the right direction on how to change either test/asyncworker.cc, test/callbackscope.cc or https://github.com/nodejs/node-addon-api/blob/master/doc/async_context.md#example to work asynchronously would be awesome. If I do get it to work in a reasonable amount of time, I promise I'll add a test and/or an example to node-addon-api.

(In order to be run on the JS thread, I'd expect I'd have to provide something like a function pointer, but I can't find anything to that effect in AsyncContext, CallbackScope, or Function::MakeCallback)

Activity

  1. twoi commented on Jan 29, 2019

    @twoi
    Author

    N.B. There is an example that seems to be doing something like I want to do, in plain N-API at https://github.com/nodejs/node-addon-examples/blob/master/async_work_thread_safe_function/node-api/

    It is using *_threadsafe_function for that, which is nowhere to be found in the node-addon-api sources, so I guess I have to go N-API for this? (But then, what would AsyncContext and CallbackScope be good for?)

  2. twoi commented on Jan 29, 2019

    @twoi
    Author

    So the *_threadsafe_function isn't even part of the N-API included in the latest node-addon-api, which would mean I have to ditch node-addon-api and do everything with lower level N-API?

  3. romandev commented on Jan 29, 2019

    @romandev
    Contributor

    @twoi, I think this issue is duplicated with #312

    So the *_threadsafe_function isn't even part of the N-API included in the latest node-addon-api, which would mean I have to ditch node-addon-api and do everything with lower level N-API?

    Yes, for now.

  4. DaAitch commented on Jan 29, 2019

    @DaAitch
    Contributor

    To your question @twoi thanks for asking.
    Short version is (I hope this is still valid):

    • AsyncWorker uses nodejs computation threads, good for async short running tasks like algorithms to not block main loop, don't do long running tasks with it, like IO or sleeping/waiting, etc., you only have a few threads (fixed size pool)
    • tsfn is for making threadsafe calls into node, so you can use whatever thread impl you want
  5. twoi commented on Jan 29, 2019

    @twoi
    Author

    Thanks @romandev @DaAitch

    But how can AsyncContext and CallbackScope be used asynchronously?

  6. twoi commented on Feb 14, 2019

    @twoi
    Author

    In the meantime, I've switched to the lower-level N-API to get the job done. It would still be great to be able to do this in node-addon-api, though. I find N-API not as easy to use as node-addon-api.

  7. gabrielschulhof commented on Feb 14, 2019

    @gabrielschulhof
    Contributor

    @twoi node-addon-api and N-API can be used together. While we don't yet have a node-addon-api wrapper around napi_threadsafe_function you can use the rest of node-addon-api together with napi_*_threadsafe_function(). You can use things like info.Env() from Napi::CallbackInfo info to obtain the napi_env you need, because a Napi::Env is automatically cast to a napi_env when you pass it into a N-API.

  8. gabrielschulhof commented on Feb 14, 2019

    @gabrielschulhof
    Contributor

    TBH I'm starting to think we should expose NAPI_THROW_IF_FAILED and NAPI_THROW_IF_FAILED_VOID because they're super-useful for mixing node-addon-api and N-API.

  9. legendecas commented on Feb 14, 2019

    @legendecas
    Member

    TBH I'm starting to think we should expose NAPI_THROW_IF_FAILED and NAPI_THROW_IF_FAILED_VOID because they're super-useful for mixing node-addon-api and N-API.

    Is there any discussion on this idea? :P having these two in future n-api would be very helpful.

  10. mhdawson commented on Mar 4, 2019

    @mhdawson
    Member

    TBH I'm starting to think we should expose NAPI_THROW_IF_FAILED and NAPI_THROW_IF_FAILED_VOID because they're super-useful for mixing node-addon-api and N-API.

    @legendecas just landed as: #448

  11. mhdawson commented on Mar 4, 2019

    @mhdawson
    Member

    @legendecas any remaining questions that need to be addressed in this issue. If not can you close it?

  12. twoi commented on Mar 4, 2019

    @twoi
    Author

    Let me close this. My question has been answered as "currently not possible with (pure) node-addon-api
    "

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

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions