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) |
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 😅 |
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:
|
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 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: |
19:14 | <Andreu Botella> |
|
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 |
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 |
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 |
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) |
23:18 | <littledan> | it seems like you can list a set of event names which shouldn't be registration-time |
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 |