10:31
<Andreu Botella>
I'm starting to get the feeling that the different use cases for AsyncContext are actually so different that for some things it won't be possible to find a behavior that works for all of them
10:32
<Andreu Botella>
APMs need different things than something like the console.log server platform example would need, which are also different from what task attribution needs
10:33
<Andreu Botella>
in particular, task attribution doesn't really care about registration, it cares about the event loop task that caused the current event loop task to run
10:34
<Andreu Botella>
and that doesn't even map to async continuation, it just so happens that for promises, you tend to call .then or await them immediately after creating/receiving them
10:37
<Andreu Botella>
use cases which so far relied on zone.js would want a mostly registration-time context for DOM events, but that doesn't work for APMs
10:37
<Andreu Botella>
I'm not sure there's a solution
10:43
<Andreu Botella>
for events I guess you could opt into some behavior in the event registation, but this also affects observers and generators
16:38
<Chengzhong Wu>
do you have a concrete case where their needs and definition are divergent?
16:44
<Andreu Botella>
Well, the various XMLHttpRequest events are fired with the context active at the time send was called
16:44
<Andreu Botella>
this is different even from task attribution's behavior with fetch, which is at async continuations (equivalent to addEventListener)
16:45
<Andreu Botella>
this is why I suspect that they don't actually need the async continuation behavior, and the context in which fetch was called might be better suited for that
16:46
<Andreu Botella>
but it just happens that most code won't see the difference for promise, whereas it might for events
16:50
<Andreu Botella>
because events tend to be registered for multiple uses, which increases the likelyhood that the registration has a different context than the immediate async cause
18:34
<Justin Ridgewell>
So Zone.js uses call time context instead of registration time?
18:39
<Andreu Botella>
No, Zone.js seems to use registration time for every event
18:40
<Justin Ridgewell>
Oh, you said task attribution doesn’t use registration time
18:40
<Andreu Botella>
If I said so, I meant the opposite
18:40
<Justin Ridgewell>
in particular, task attribution doesn't really care about registration, it cares about the event loop task that caused the current event loop task to run
18:41
<Justin Ridgewell>
Maybe I misunderstand
18:41
<Justin Ridgewell>
(Or I confused you with my edit)
18:41
<Steve Hicks>
FWIW, registration time by default makes it a lot harder to maintain the cause's context, whereas cause-by-default can restore registration time with a simple call to wrap.
18:42
<Andreu Botella>
(Or I confused you with my edit)
That, and I'm currently in the middle of walking my dog 😅
18:43
<Justin Ridgewell>
So for attribution, if I do el.addEventListener(‘click’, () => {}), they want to propagate the context that happens during the trigger?
18:43
<Justin Ridgewell>
That, and I'm currently in the middle of walking my dog 😅
SEND PICS PLZ
18:54
<Andreu Botella>
Task attribution doesn't seem to care too much about most events, since it's not something that can be queried by JS code. The default is call-time, and that's the case for the click event
18:55
<Andreu Botella>
So el.click() (which fires the event synchronously) uses the call-time context, and clicks coming from the user are fired in the empty context
18:56
<Andreu Botella>
The only things which are registration-time in task attribution are web APIs which schedule a callback: setTimeout, requestAnimationFrame, scheduler.postTask...
19:05
<Justin Ridgewell>
So a coulple of questions:
  1. Is call-time behavior necessary for Task Attribution? (Probably yes?)

  2. Do we feel that registration-time is correct for AC? (I think so, but could be persuaded)

19:06
<Justin Ridgewell>
If we don’t match Task Attribution’s semantics, then we cannot share the same CPED pointer in the job records
19:07
<Justin Ridgewell>
We’d need to reevaluate our performance/memory impact since we’d need a new pointer.
19:08
<Andreu Botella>
If we don’t match Task Attribution’s semantics, then we cannot share the same CPED pointer in the job records
It could be shared if the code in Blink that sets the propagation has task attribution in mind, but that would mean turning what would be AsyncContext.Snapshot.p.run into an AsyncContext.Variable.p.run
19:08
<Andreu Botella>
which would have memory and performance effects
19:10
<Justin Ridgewell>
I don’t understand, how would that work?
19:11
<Justin Ridgewell>
Would the click() restore the snapshot, then run a taskAttribution.run(callTime, …)?
19:11
<Andreu Botella>
yeah
19:12
<Justin Ridgewell>
Ok, that’s not terrible
19:13
<Justin Ridgewell>
If we had a fixed key slot for attribution, we could make that reasonably fast
19:13
<Justin Ridgewell>
Instead of storing attribution inside the HAMT with the user variables
19:14
<Andreu Botella>
So a coulple of questions:
  1. Is call-time behavior necessary for Task Attribution? (Probably yes?)

  2. Do we feel that registration-time is correct for AC? (I think so, but could be persuaded)

about 1, I asked Scott Haseley last week, and these were his initial thoughts
19:14
<Andreu Botella>

It might be okay, but I'll need to think about it and discuss with the team -- and some folks are out this week. Initial concerns/uncertainties:

  • This could impact soft navigation because code running within a soft nav task-attributable task will have a different context, e.g. an event fired within a click or setTimeout. Is this okay (not sure)? Either way it could change reported soft navs, so we'd need to run experiments (assuming the soft nav context isn't automatically plumbed through).
  • We previously created a new TaskScope for every event/callback, which we changed because of performance issues, so we'd need to be really careful here.
19:15
<Andreu Botella>
TaskScope is the equivalent of a Variable.p.run
19:24
<Justin Ridgewell>
Ok, worse case we could add a host-hook before we set the context when restoring a snapshot
19:24
<Justin Ridgewell>
That way engines could perform whatever call-time modification they need
19:24
<Justin Ridgewell>
Though now I’m curious when they don’t need a new TaskScope
19:27
<Andreu Botella>
Ok, worse case we could add a host-hook before we set the context when restoring a snapshot
I think the only chance that this might be needed for task attribution is if whatever we end up deciding for generators doesn't end up working for them (which I doubt will happen)
19:27
<Andreu Botella>
because they're fine with the CPED behavior, and anything else would be Blink calling the V8 embedder API
19:28
<Justin Ridgewell>
I think the ordering is incorrect, which will require it
19:28
<Justin Ridgewell>
Actually, no, for regular addEventListener() they should be fine
19:29
<Justin Ridgewell>
I was thinking we did AC.wrap(listener) on the V8 side, but we don't
19:29
<Justin Ridgewell>
But, how would Attribution work when I invoke a snapshot.run(foo)?
19:30
<Justin Ridgewell>
Should the current TaskScope be kept, or is it ok to restore the snapshot’s?
19:31
<Andreu Botella>
When I talked with Yoav Weiss, the conclusion was that it would be fine to restore the snapshot's, because that is already a thing you can do with promises, although it's obviously not as accessible
19:31
<Andreu Botella>
but I haven't discussed this with Scott
19:48
<Steve Hicks>
Unrelated (so maybe respond in a thread): have we thought about dynamic import (with top-level await)? In particular, does the imported module run in the context of the importer, or in the root context?
19:49
<Andreu Botella>
huh, I hadn't thought of that
19:50
<Andreu Botella>
task attribution does something for script and module evaluation, but I haven't looked at it in any detail
19:51
<Justin Ridgewell>
We discussed that a bit in the SES meeting, I think they were expecting it to run within the context of the importer
19:52
<Justin Ridgewell>
That’s my thought as well
19:57
<Justin Ridgewell>
That probably makes it difficult to polyfil, huh?
19:59
<Andreu Botella>
if we end up having things in the web integration that aren't exactly call time or registration time, but instead some async originating context, that would probably be impossible to polyfill
19:59
<Justin Ridgewell>
It would require bundler integration to do properly
22:36
<littledan>
I'm starting to get the feeling that the different use cases for AsyncContext are actually so different that for some things it won't be possible to find a behavior that works for all of them
OK, this is possible, and people have claimed it, but for me to understand it better, it would help me to see concrete examples of where different behavior would make sense for the same callback, depending on the context. Are you working on collecting any examples like this?
22:37
<littledan>
something I've heard claimed is that certain variables make sense to treat in different ways than other variables
22:38
<littledan>
anyway if it turns out that this is intractably bad, we can withdraw the proposal (it has been raised as a counterargument before), but I'm not at all convinced that the requirements for different environments are different.
22:38
<Andreu Botella>
I'm not arguing at this point that this is intractable
22:39
<littledan>
could you characterize the difference in any more detail?
22:39
<Andreu Botella>
but I'm fearing that it might be the case
22:39
<littledan>
right, so, I'd like to understand what's behind that fear
22:42
<littledan>
I think it'd be helpful if we had a table of different functions which take callbacks, and then we can think about various different policies for which snapshot they should restore. You had something like this in progress, right? Were there any particularly challenging "rows" that you encountered?
22:43
<Andreu Botella>
well, for every single event, task attribution's behavior is different from zone.js's
22:43
<littledan>
could you give a concrete example and we can think through what's useful?
22:48
<Andreu Botella>
the example that made me realize that task attribution's use case is probably quite different from most users of AsyncContext is that task attribution recently made the XMLHttpRequest events have the context of the send() call
22:49
<Andreu Botella>
whereas before it just had an empty context (which is the default for async events in task attribution)
22:49
<Andreu Botella>
note that this is different from fetch
22:49
<Andreu Botella>
even in task attribution
22:49
<littledan>
OK, so let's think about XMLHttpRequest and fetch. What are the semantics in zone.js and task attribution of each?
22:49
<littledan>
we should probably add AsyncLocalStorage's semantics as well to that list, at least for fetch
22:50
<littledan>
oh I guess fetch doesn't have a callback so this doesn't come up? it's just from promises?
22:50
<Andreu Botella>
yeah
22:50
<littledan>
I would very much not assume that either of those two implementations (zone.js or task attribution) is perfect and has semantics that we must preserve exactly as they are. We should think about what is important about their behavior for their users.
22:51
<littledan>
they are just reference points that are useful in an investigation
22:51
<Andreu Botella>
yeah, and indeed I think task attribution is not perfect here
22:51
<Andreu Botella>
at least for what I think they need
22:51
<littledan>
(also XHR is legacy; it would somehow be easier to think about something which isn't so deprecated)
22:52
<Andreu Botella>
well, the fact that this was different in XHR and fetch was what made me realize the different semantics
22:52
<littledan>
OK, what are the semantics of each, in each framework?
22:52
<littledan>
oh I see you explained in a thread
22:52
<littledan>
https://matrix.to/#/!eQuZUAhGqudVFPodUG:matrix.org/$MWb8YUBP-AfcdHf9n2LVI-EIbo390545jUohOKlSZ6Q?via=matrix.org&via=mozilla.org&via=igalia.com
22:53
<Andreu Botella>
since fetch returns a promise, ALS, task attribution and zone.js all propagate the context at the point that the promise is awaited or called .then()
22:53
<Andreu Botella>
not the context at which fetch() is called
22:54
<Andreu Botella>
in XHR, calling fetch() would be equivalent to calling either open() or send() – it doesn't really matter which, but task attribution uses send()
22:54
<Andreu Botella>
and that is the context that task attribution propagates
22:54
<littledan>
let's just focus on XHR onto itself. Is this consistent between zone.js and task attribution?
22:54
<Andreu Botella>
no, zone.js uses the registration-time context (for addEventListener)
22:55
<littledan>
So, let's think, when do we expect these contexts to differ?
22:56
<littledan>
we've already made calls in this proposal that it's OK for us to change semantics slightly if we expect the contexts to be equal in practice (e.g., for unhandled promise rejections)
22:56
<littledan>
I think, with XHR, you tend to create it, add the events, and send it all in one piece of JS
22:57
<Andreu Botella>
IIRC the XMLHttpRequest object can be reused for multiple fetches, but it tends not to be
22:57
<Andreu Botella>
and this is very different from something long lived like a DOM element, document, window...
22:58
<littledan>
I wonder if we can find any old zone.js bug report/incremental development around this. I'll ask my Angular contacts.
22:58
<littledan>
Have you run into anything else besides XHR?
22:58
<littledan>
setTimeout is unambiguous, for example, right?
22:59
<Andreu Botella>
yeah, for web APIs which schedule a callback, there is only one possible context that could be used
23:11
<littledan>
OK, I suspect that this particular case is one where either answer would be fine... it'll be good to dig into another one once we think of it
23:12
<Andreu Botella>
I think I should focus on which possible contexts would make sense for each event, rather than on what task attribution or zone.js do
23:13
<Andreu Botella>
I suspect that's more likely to give us general rules
23:14
<littledan>
I agree; those two are interesting reference points to keep in mind, but we're not going for 100% backwards compatibility with either.
23:14
<littledan>
I suggested looking at those because they represent some accumulation of knowledge/experience in this area
23:14
<Justin Ridgewell>
I think it’s still useful to consider which context Zone.js uses for each API
23:15
<Justin Ridgewell>
We don’t need to be 100% compatible, but we should have a good reason for breaking with it.
23:15
<Andreu Botella>
zone.js's behavior seems to be to use registration time on every event, except that it allows overriding the behavior for different events
23:15
<Andreu Botella>
although it's not fully consistent in that
23:15
<littledan>
It would be easier for me to understand these descriptions of what zone.js does based on concrete examples, and what we think of them
23:15
<Andreu Botella>
(i.e. MessagePort.p.onmessage is call-time, but the message event on MessagePort is registration-time)
23:16
<Justin Ridgewell>
Even if it’s always registraiton time, we still need to list out each of the APIs we expect will integrate with AC
23:16
<littledan>
also what kind of overriding they allow (we have AsyncContext.Snapshot.wrap for certain kinds of overriding, but I'm not sure whether or not this models everything)
23:16
<Justin Ridgewell>
That way we can discuss with the Shu and Dan Minor
23:16
<littledan>
Even if it’s always registraiton time, we still need to list out each of the APIs we expect will integrate with AC
yes, either that or make a uniform change in WebIDL. But I think we should list out many APIs to make sure we're specifying the behavior that we want to actually happen.
23:17
<littledan>
the ideal case would be something that's uniform in some way or other. I just don't know what that policy is (people have posited directly contradictory general rules), and I think we will be able to derive this best from examples.
23:17
<Andreu Botella>
also what kind of overriding they allow (we have AsyncContext.Snapshot.wrap for certain kinds of overriding, but I'm not sure whether or not this models everything)
it seems like you can list a set of event names which shouldn't be registration-time
23:18
<littledan>
it seems like you can list a set of event names which shouldn't be registration-time
yep, that's one possibility! and this can be expressed in WebIDL with things like extended attributes.
23:18
<littledan>
but first is figuring this out through concrete examples. Something can look scary in the abstract but then prove to be small/easy when you examine it concretely.
23:19
<littledan>
or, "obviously" one way in the abstract, when under concrete inspection, it is clearly wrong