00:08
<littledan>
Well it turns out Yoav found a word of memory that he could use in promise reactions that existed for other reasons. I haven’t learned details yet. It’s also possible that this doesn’t work for other engines though
00:09
<littledan>
One piece of feedback: Yoav got the idea from the readme that this feature was mostly for APMs. We should encorporate the examples from the slide deck into the readme and talk them through.
00:10
<littledan>
Because, we have to work especially hard to explain to browsers why this is their problem. APMs are already sold on the importance of this space
00:12
<James M Snell>
one key thing here (simply because it's fresh on my mind) is that whatever mechanism is used to implement this in engines like v8, embedders need the ability to define their own async resources (timers, other objects, etc). There has to be some API, for instance, that we can use internally in node.js and workers, etc to set the current async resource independently of promises.
00:13
<Justin Ridgewell>
One piece of feedback: Yoav got the idea from the readme that this feature was mostly for APMs. We should encorporate the examples from the slide deck into the readme and talk them through.
What is an APM?
00:13
<James M Snell>
APM = Application Performance Monitors (think datadog, new relic, etc)
00:14
<littledan>
one key thing here (simply because it's fresh on my mind) is that whatever mechanism is used to implement this in engines like v8, embedders need the ability to define their own async resources (timers, other objects, etc). There has to be some API, for instance, that we can use internally in node.js and workers, etc to set the current async resource independently of promises.
Yeah, the web needs this as well—this is what attracted Yoav to the area. I hope this can be modeled as the embedded simply creating an AsyncContext and using the three core operations. We should look into the use cases so we can verify that this works.
00:15
<littledan>
APM = Application Performance Monitors (think datadog, new relic, etc)
Things that hack into Node.JS to help you measure and optimize performance
00:15
<Justin Ridgewell>
one key thing here (simply because it's fresh on my mind) is that whatever mechanism is used to implement this in engines like v8, embedders need the ability to define their own async resources (timers, other objects, etc). There has to be some API, for instance, that we can use internally in node.js and workers, etc to set the current async resource independently of promises.
I believe that is handled by the static wrap method?
00:15
<littledan>
Hack in the nicest sense of the word! Maybe!
00:15
<James M Snell>
If it helps from a use case perspective, I've started the implementation of AsyncLocalStorage in workerd (cloudflare workers) https://github.com/cloudflare/workerd/pull/208
00:16
<littledan>
If it helps from a use case perspective, I've started the implementation of AsyncLocalStorage in workerd (cloudflare workers) https://github.com/cloudflare/workerd/pull/208
So… how fast would we need to deliver AsyncContext in TC39 to take the pressure off of you to ship AsyncLocalStorage in workerd?
00:16
<James M Snell>
provides a decent contrast to Node.js' implementation because (a) it's simpler (fewer async resources) and (b) there is no async_hooks api)
00:16
<James M Snell>

how fast would we need to deliver AsyncContext in TC39

Weeks?

00:16
<James M Snell>
We have customers who have been clamoring for this for a while now
00:17
<littledan>
Hehe Ok
00:17
<littledan>
Anyway AsyncContext will be a point of longer term compatibility
00:17
<James M Snell>
we absolutely have to make sure, however, that whatever is produced by TC-39 here is compatible. Our intent would be to update AsyncLocalStorage to be a thin shim layer on top of whatever v8 gives us later
00:18
<littledan>
we absolutely have to make sure, however, that whatever is produced by TC-39 here is compatible. Our intent would be to update AsyncLocalStorage to be a thin shim layer on top of whatever v8 gives us later
Whether this is the case depends on the exact subset you are using... will review
00:19
<James M Snell>
For ALS -> run(), exit() and getStore()
00:19
<James M Snell>
we are not implementing enterWith() or disable()
00:19
<Justin Ridgewell>
Why do you need the exit method?
00:19
<James M Snell>
We are implementing AsyncResource also without the async_hooks api details
00:20
<James M Snell>
Our implementation of exit() is really run() and passing undefined
00:20
<Justin Ridgewell>
That’s the only thing that doesn’t have a direct parallel.
00:20
<Justin Ridgewell>
Ah, ok
00:20
<littledan>
So you don’t have a facility for queuing in libraries, just in the runtime?
00:21
<James M Snell>
not currently but that could change
00:21
<James M Snell>
we just don't need that at the moment
00:22
<James M Snell>
we will expose the AsyncResource object to allow user code to create their own contexts
00:22
<James M Snell>
but that's about it
00:23
<littledan>
OK, sounds like that is the equivalent of wrap
00:24
<James M Snell>
exactly
00:24
<littledan>
And the expressiveness is identical overall
00:24
<littledan>
OK perfect
00:24
<James M Snell>
It's to support stuff like stuff like addEventListener('foo', asyncResource.bind(()=> { /* executes in asyncResource's context */ });
00:25
<Justin Ridgewell>
I think there are a couple of a APIs on asyncresource that might not be compatible, but if you do another minimal API, it should be fine
00:25
<littledan>
IMO this is an interesting story to motivate the project that warrants sharing with others sometimes—at least with other server JS environments so they don’t overstep in ALS compat! But also to justify the whole project.
00:26
<James M Snell>
For AsyncResource we are only implementing bind() (static and member), runInAsyncScope(), asyncId() and triggerAsyncId()
00:27
<littledan>
Is AsyncResource just about restoring a particular AsyncContext or does it do all of them?
00:27
<Justin Ridgewell>
I’m not familiar with the IDs, but the rest should be fine
00:28
<littledan>
I guess the id stuff is a small layer on top
00:30
<James M Snell>

It's really about providing a root for a context... for instance, if I did

const als = new AsyncLocalStorage();
const fn = als.run(123, () => AsyncResource.bind(() => console.log(als.getStore()));
eventTarget.addEventListener('foo', fn);
eventTarget.addEventListener('foo', () => console.log(als.getStore());

The first listener prints 123, the second undefined

00:30
<James M Snell>
The id stuff is just part of Node.ks
00:30
<James M Snell>
it doesn't yet give us any other way of identifying the parent explicitly when creating a new AsyncResource