use single phase of resolver abortSignal cancellation#4554
use single phase of resolver abortSignal cancellation#4554yaacovCR merged 1 commit intographql:nextfrom
Conversation
|
@yaacovCR is attempting to deploy a commit to the The GraphQL Foundation Team on Vercel. A member of the Team first needs to authorize it. |
157dec2 to
c81de26
Compare
Previously, we used a lazily created abortSignal per resolver so as to shift triggering the abortSignal for a resolver that returned a streamed asyncIterable from the original executor to the stream. This is expensive and difficult to reason about and has been replaced by a single phase of cancellation when the entire execution finishes. Note: when executing a subscription, we are still able to cancel resolver abortSignals after execution of each subscription event.
c81de26 to
fb285c6
Compare
|
In particular, the "confusion" regarding tying resolver abortSignals to particular Executors lies with incremental delivery. What we'd like to do is trigger the abortSignal if that resolver should be cancelled because of null bubbling, but we don't currently have a mechanism to scan downwards in the path tree from the location to which the null bubbles. So what we do instead is just wait until execution "ends" and trigger the abortSignal for all resolvers. But, in a situation of incremental delivery, if we scope the abortSignal to each individual executor, i.e. the root Executor and child executionGroup/streamItem Executors, we can no longer reliably trigger the abortSignal in all situations. Namely, for a resolver returning an async iterable for a list field that streams, the abortSignal could be checked in the middle of that stream, so if the abortSignal is scoped to the root executor, it would fire early. And so we end up having to create new abort controllers/signals for every resolver and move them from being triggered by the end of the root executor or the end of the stream, depending on whether they are streamed. (And that's putting aside that in theory a resolver can return a construct that is fed forward into descendant fields, that in theory could misbehave once the parent abortSignal is triggered.) Performing a single phase of abortSignal cancellation at the entire end of execution obviates all of the above, at the expense, of course, of delaying cancellation. |
Previously, we used a lazily created abortSignal per resolver so as to shift triggering the abortSignal for a resolver that returned a streamed asyncIterable from the original executor to the stream. This is expensive and difficult to reason about and has been replaced by a single phase of cancellation when the entire execution finishes.
Note: when executing a subscription, we are still able to cancel resolver abortSignals after execution of each subscription event.
Additional note: this is labelled "bug fix" rather than "polish" because it is technically observable.