async_hooks: add AsyncLocal class#27172
async_hooks: add AsyncLocal class#27172Flarna wants to merge 6 commits intonodejs:masterfrom Flarna:async_local
Conversation
lib/async_hooks.js
Outdated
There was a problem hiding this comment.
This invocation is very risky. User callbask should be called outside of async hooks.
There was a problem hiding this comment.
Well, then it will not work as moving it outside of async hooks would require something like nextTick which is a new async operation. As a result the signaled values and the real values don't match anymore.
There was a problem hiding this comment.
If this cannot be made safe, I don't think supporting this "onchanged" behavior is compatible for the goal of "ease of use" that this API is supposed to have.
There was a problem hiding this comment.
I will improve docs in this, add a check to catch recursion cases (e.g. onChangedCb sets a new value) and handle exceptions thrown by onChangedCb. Hopefully this renders this callback as save as all the other callbacks which can be registered in node core.
lib/async_hooks.js
Outdated
There was a problem hiding this comment.
If this cannot be made safe, I don't think supporting this "onchanged" behavior is compatible for the goal of "ease of use" that this API is supposed to have.
|
Judging by the included example, it's difficult to see why we would ever need more than one instance of |
|
I'm in agreement with @mcollina on the callback issue. It's not clear if there's a safe way of doing that. On the const { setAsyncLocal, getAsyncLocal } = require('async_hooks');
const value = { /* ... */ };
setAsyncLocal(value);
// ...
const value = getAsyncLocal();
// ...
setAsyncLocal(); // Reset to undefined |
|
I think building proper namespaces into the API makes sense (as opposed to having one singleton). E.g. the application may want to track its own metadata while also using a 3rd party/APM tool that may use these APIs. With a singleton, that seems to be a bit dangerous (🤞 that no keys are reused). |
Actually I had two targets in mind with this:
By the way, I don't understand why a user callbacks here is more dangerous then in async hooks itself or in any other place where I can install a callback. Maybe it's just a mater of adding more documentation that it may be called "frequently" and that async operations should be not triggered there similar as we have it in async_hooks currently. Regarding singleton: I don't think this will fit well if you consider independent users, e.g. an APM, a Logger. They should be isolated similar as they would be isolated if using a thread local in a thread based system. The |
|
/cc @misterdjules (you may be interested) |
|
I added some more docs and a check to disallow setting of a new value from the @mcollina @jasnell Please let me know if you think this callback is now as safe as other callbacks. |
This introduces a new API to provide asynchronous storage via a new AsyncLocal class. Besides setting a value which is passed along asynchronous invocations it allows to register a callback to get informed about changes of the current value. The implementation is based on async_hooks but it doesn't expose internals like execution Ids, resources or the hooks itself. Naming and implementation is inspired by .NET AsyncLocal.
|
Closing as it seems there is not much interest in this and there are other PRs implementing parts of this. Besides that some more work would be needed:
Maybe I will publish this as an userspace module at some time |
This introduces a new API to provide asynchronous storage via a new
AsyncLocal class. Besides setting a value which is passed along
asynchronous invocations it allows to register a callback to get
informed about changes of the current value.
The implementation is based on async_hooks but it doesn't expose
internals like execution Ids, resources or the hooks itself.
Naming and implementation is inspired by .NET AsyncLocal.
There is already #26540 adding similar functionality then this one and
we should for sure not add both.
I'm not sure if creating a new PR in parallel is the best way to
discuss this but I think it's the easiest variant to allow anyone to
give both a try.
Main differences between #26540 and this one:
As prove of concept I tried locally to port domains to use
AsyncLocalinsteadasync_hooks. I was able to get all tests green except 3 base on native
addons using a
domainproperty on the resource which seems to be deprecatedmeanwhile so I stopped there. The notification callback was needed to get this far.
Refs: https://docs.microsoft.com/en-us/dotnet/api/system.threading.asynclocal-1?view=netframework-4.7.2
Refs: #26540
fyi @nodejs/diagnostics @watson @vdeturckheim
Checklist
make -j4 test(UNIX), orvcbuild test(Windows) passes