-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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
Integrate C++ AsyncHooks Embedder API with native abstraction #13254
Comments
I can’t really speak for NAN; my best guess is that it will want to build its own thing similar to As for N-API: I’m not sure. We could just proxy the low-level API to C and add a One thought I’ve had is that we could add a |
I need to familiarize myself more with this, but initially I think @addaleax is right in that it would be better to make a new class for this (new) concept. Another question is that of compatibility. How far back can this be implemented without patching node.js? |
I'm not exactly sure what "new" covers, I see this as adding annotation to existing functionality. My thoughts behind annotating Adoption by userland is critical in this case, because if just one native addon model is missing the annotation then the usefulness of AsyncHooks is dramatically decreased.
Currently, AsyncHooks will only be in node v8.x, we may backport it to v6.x and perhaps even v4.x. As said the AsyncHooks Embedder API should be seen as annotation, thus for node versions where the AsyncHooks Embedder API is not supported that annotation simply won't be added. |
I agree – once
I’m pretty sure we won’t backport to v4.x? |
I do not know what the explicit usage rate of I am not sure what "new" covers either, which is why I need to read up on what async hooks are supposed to do before I can make an informed statement. However, the point of NAN is to offer a set of functionality that gives the same observable behavior on all supported versions of Node.js. There should not be anything that only works on specific versions, since that would defeat the point of having a version-independence abstraction layer. An end-user should be able to assume that all code does what it should on all supported versions. This also includes not having functionality that becomes a no-op on certain versions, since that hides that the code does not work as intended. That being said, if all this does is adding some extra information which can be useful in some cases, there might be a way to add some of it to NAN so that code running on newer versions of node.js does something in a better or more efficient manner. For instance, if async hooks subsumes an older API which may then be deprecated, the NAN code for all newer versions that support this functionality could be made to use it instead of the older functionality, since that would fall within implementation, not version-independent functionality. To make this a bit clearer: We can think of two aspects of NAN: One is the external, documented API. Only functionality which works on all supported versions goes here. The other is the internal implementation (actually there are several of them depending on node version), which has greater freedom. Here, the only restriction is: Given a program in state S which calls a part of NAN, at return from NAN, the program is in state S', regardless of which version-dependent implementation was used. |
I think it should be easy enough to add support for everything we need to
You mean, that works from the addon writer’s perspective, right? It would be okay if Nan had code that only worked well with the versions of Node to which Also: Would it help if Node had a |
Yes, from the addon writer's perspective, if a (documented) function appears in NAN, the contract states that it works the same on all versions of Node.js. Suppose a function in NAN returns an object with a set of keys and values. Those keys and values should be the same on all versions of Node. In some specific instances it might be allowable to allow more keys and values to appear, but then they fall out of NAN's blessing, not documented by NAN and are used at your own risk (usually because we would not take active steps to remove kv-pairs if that returned object was obtained from, say, a V8 function). Sniffing specific versions of Node from NODE_MODULE_VERSION and NODE_VERSION is not too hard, there are only ever problems when nonstandard implementations which are not Node but claim to be so enter the picture, and I suspect a special define could end up meaningless there too... |
From what I now have gleaned about what the async hooks are supposed to do, it seems that all NAN needs to do is change implementations of relevant existing APIs for versions of Node that support async hooks so that async hooks transparently work, since the end user may want to use async hooks while running on newer versions of Node, while still using NAN. Since no new external APIs related to async hooks need to be added, that should be perfectly fine. It is a matter of transparency, or not getting in the way. |
@matthewloring and I had a discussion yesterday about exposing APIs for async hooks in N-API, and I've started looking into this further. Before proposing a design, I have a few questions:
|
It's only a double b/c that's the only numeric type that JS supports, and the async id is assigned as an object property for quick lookup. Can you explain what you mean by "opaque" more?
That API exists in in JS and would be possible in C++, but @AndreasMadsen is more knowledgeable as to whether there would be any issues doing this. |
It is provided by default but the usual scenario is going to be that the trigger ID is inferred from context.
The typedef is a somewhat intentional step towards making it opaque, yes. It might still be good to be able to log the value, or to pass it to JS and have it comparable to the values JS sees.
Maybe/probably? It should not be hard, and while it would be really nice to have domains implementable in terms of async_hooks, we’re not there yet.
@trevnorris Not sure what you mean, the C++ API for this already exists. Imo, the main thing that N-APi should focus on for now is enabling async_hooks and domains for the |
@addaleax is right. I want to add that there is no API for getting the default value, other than
I have sometimes abused the fact that the double is increasing with time, which makes it an easy sortkey and thus I can use some clever graph hacks. But it should be opaque. Perhaps, at some point in the future we will use
I'm flattered, but I will mostly defer to @addaleax as she wrote that code. In the future I think we would like to rewrite domains to use |
By the way, I tried that a while back, and… the tricky bit isn’t implementing domains on top of |
Nevermind me. Was thinking of something else. It's what I get for trying to respond to issues while in a meeting.
When My initial work on this is at nodejs/node-v0.x-archive@bc39bdd but after the month of effort getting the async error handling down correctly I decided to give up. Unfortunately the commits for those changes were lost when I deleted my |
I don't understand that reasoning. It could easily be treated as an integer in the native API. While working on performance optimizations for N-API, I found that creating a V8 number value is somewhat faster using
A pointer to an undefined structure. N-API uses opaque pointers for some things so that the actual type or structure of a value is hidden from user code and can change without breaking ABI stability.
|
First Nan PR: nodejs/nan#729 |
This commit adds support for the async context accepting versions of node::MakeCallback. An async_context concept has been added as a wrapper around node::async_context, along with APIs for initializing and destroying async context, similar to how [N-API][] exposes this functionality. Ref: nodejs/node#13254 [N-API]: https://nodejs.org/dist/latest-v9.x/docs/api/n-api.html#n_api_custom_asynchronous_operations
Deprecation of legacy |
This commit adds support for the AsyncResource API to allow native modules to asynchronously call back into JavaScript while preserving node's async context. This acts as a higher level alternative to the MakeCallback API. This is analogous to the AsyncResource JavaScript class exposed by [async_hooks][] and similar to the `napi_async_init`, `napi_async_destroy` and `napi_make_callback` APIs, albeit wrapped in a convenient RAII form-factor. Ref: nodejs/node#13254 [N-API]: https://nodejs.org/dist/latest-v9.x/docs/api/n-api.html#n_api_custom_asynchronous_operations [async_hooks]: https://nodejs.org/api/async_hooks.html
This commit adds support for the AsyncResource API to allow native modules to asynchronously call back into JavaScript while preserving node's async context. This acts as a higher level alternative to the MakeCallback API. This is analogous to the AsyncResource JavaScript class exposed by [async_hooks][] and similar to the `napi_async_init`, `napi_async_destroy` and `napi_make_callback` APIs, albeit wrapped in a convenient RAII form-factor. Ref: nodejs/node#13254 [N-API]: https://nodejs.org/dist/latest-v9.x/docs/api/n-api.html#n_api_custom_asynchronous_operations [async_hooks]: https://nodejs.org/api/async_hooks.html
Nan::AsyncWorker and Nan::Callback support: nodejs/nan#731 |
The legacy MakeCallback functions do not provide a mechanism to propagate async context. This means that any native modules using these directly is likely breaking async debugging & tracing tools. For examples it is possible that such a module will cause incorrect async stack traces to be reported (even when the module is not on the stack). The new MakeCallback allow the user to specify the async context in which the callback is to be executed. Ref: nodejs#13254 PR-URL: nodejs#18632 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Evan Lucas <[email protected]> Reviewed-By: Jan Krems <[email protected]> Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
The legacy MakeCallback functions do not provide a mechanism to propagate async context. This means that any native modules using these directly is likely breaking async debugging & tracing tools. For example it is possible that such a module will cause incorrect async stack traces to be reported (even when the module is not on the stack). The new MakeCallback allow the user to specify the async context in which the callback is to be executed. Ref: nodejs#13254 PR-URL: nodejs#18632 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Evan Lucas <[email protected]> Reviewed-By: Jan Krems <[email protected]> Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Gibson Fahnestock <[email protected]>
With the |
Thanks @ofrobots for driving this. :) |
- Add napi_async_context opaque pointer type. (If needed, we could later add APIs for getting the async IDs out of this context.) - Add napi_async_init() and napi_async_destroy() APIs. - Add async_context parameter to napi_make_callback(). - Add code and checks to test_make_callback to validate async context APIs by checking async hooks are called with correct context. - Update API documentation. PR-URL: nodejs#15189 Fixes: nodejs#13254 Reviewed-By: Michael Dawson <[email protected]> Reviewed-By: James M Snell <[email protected]>
- Add napi_async_context opaque pointer type. (If needed, we could later add APIs for getting the async IDs out of this context.) - Add napi_async_init() and napi_async_destroy() APIs. - Add async_context parameter to napi_make_callback(). - Add code and checks to test_make_callback to validate async context APIs by checking async hooks are called with correct context. - Update API documentation. Backport-PR-URL: #19447 PR-URL: #15189 Fixes: #13254 Reviewed-By: Michael Dawson <[email protected]> Reviewed-By: James M Snell <[email protected]>
The legacy MakeCallback functions do not provide a mechanism to propagate async context. This means that any native modules using these directly is likely breaking async debugging & tracing tools. For example it is possible that such a module will cause incorrect async stack traces to be reported (even when the module is not on the stack). The new MakeCallback allow the user to specify the async context in which the callback is to be executed. Ref: nodejs#13254 PR-URL: nodejs#18632 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Evan Lucas <[email protected]> Reviewed-By: Jan Krems <[email protected]> Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Gibson Fahnestock <[email protected]>
This commit adds support for the AsyncResource API to allow native modules to asynchronously call back into JavaScript while preserving node's async context. This acts as a higher level alternative to the MakeCallback API. This is analogous to the AsyncResource JavaScript class exposed by [async_hooks][] and similar to the `napi_async_init`, `napi_async_destroy` and `napi_make_callback` APIs, albeit wrapped in a convenient RAII form-factor. Ref: nodejs/node#13254 [N-API]: https://nodejs.org/dist/latest-v9.x/docs/api/n-api.html#n_api_custom_asynchronous_operations [async_hooks]: https://nodejs.org/api/async_hooks.html
The AsyncHooks Embedder API has now been merged, we need to integrate this into N-API and NAN such that userland add-ons can inform
async_hooks
about the context.I'm not very familiar with either APIs, but NAN is the API I know the best, so I will explain it from that perspective.
AsyncHooks allows userland to get notified about all asynchronous event and understand what caused the asynchronous job to be tasked. This requires 4 events to be emitted:
init
: emitted with the asynchronous job is created (called a resource).EmitAsyncInit
emits this.before
,after
: emitted with the asynchronous job calls back, this can happen multiple times.MakeCallback
now emits these when two additional parameters are passed (async_id
andtrigger_id
).destroy
: emitted when the resource can't call back anymore.EmitAsyncDestroy
emits this.there is also a high-level API, a C++ class called
AsyncResource
but I suspect this isn't useful for NAN or N-API.In terms of NAN I think there is almost a 1 to 1 mapping between
Nan::Callback
and the AsyncHooks API. I believe the following changes should be made:Callback::Callback
should calltrigger_id = AsyncHooksGetTriggerId(isolate);
anduid = EmitAsyncInit(isolate, resource, name, trigger_id);
.Callback::Call
should callnode::MakeCallback(isolate, resource, callback, argc, argv, uid, trigger_id);
Callback::~Callback
should callEmitAsyncDestroy(isolate, uid);
This is very similar to the
AsyncResource
class. It is not clear what theresource
should be asCallback::Callback
does not take such a parameter.I believe @mhdawson said during a diagnostics meeting that if NAN required changes then likely N-API would need changes too.
/cc @mhdawson @addaleax @trevnorris @nodejs/diagnostics @nodejs/n-api @nodejs/addon-api @nodejs/nan (@kkoopa)
The text was updated successfully, but these errors were encountered: