Commit fcf5a8a
committed
feat(execution): expose async-work-finished execution hook
access finalization of all tracked async work beyond that included in the result via experimental hook
Access the asyncWorkFinished hook via `experimentalHooks` on execution args:
```ts
const result = execute({
schema,
document: parse('{ test }'),
experimentalHooks: {
queryOrMutationOrSubscriptionEventAsyncWorkFinished({
validatedExecutionArgs,
}) {
const operationName =
validatedExecutionArgs.operationName ?? '<anonymous>';
console.log(`async work finished for operation: ${operationName}`);
},
},
});
```
`execute(...)` can return synchronously (for example after a synchronous bubbled
error) while tracked async work is still pending. To always get a Promise that
resolves only after this hook is called:
```ts
const args: ExecutionArgs = {
schema,
document: parse('{ test }'),
};
let hookCalled = false;
let resolveAsyncWorkFinished: (() => void) | undefined;
const asyncWorkFinished = new Promise<void>((resolve) => {
resolveAsyncWorkFinished = resolve;
});
const existingHook =
args.experimentalHooks
?.queryOrMutationOrSubscriptionEventAsyncWorkFinished;
const result = execute({
...args,
experimentalHooks: {
...(args.experimentalHooks ?? {}),
queryOrMutationOrSubscriptionEventAsyncWorkFinished(info) {
try {
existingHook?.(info);
} finally {
hookCalled = true;
resolveAsyncWorkFinished?.();
}
},
},
});
const resultAfterAsyncWorkFinished: Promise<ExecutionResult> =
Promise.resolve(result).then((executionResult) =>
hookCalled
? executionResult
: asyncWorkFinished.then(() => executionResult),
);
```
This is safe whether `result` is sync or async, and whether the hook callback is
reached immediately or later.
Async work started inside resolvers is not automatically guaranteed to be tracked.
For example, `Promise.all([...])` rejects on the first rejection, so sibling promises
may still be pending after `execute(...)` has already produced a result.
Use `info.getAsyncHelpers()` to include that work in async tracking:
```ts
resolve(_source, _args, _context, info) {
const { promiseAll } = info.getAsyncHelpers();
return promiseAll([
fetchFromA(),
fetchFromB(),
fetchFromC(),
]);
}
```
`promiseAny` and `promiseRace` similarly track non-winning/non-settled promises,
and `trackPromise` can be used for any additional Promise you want included:
```ts
resolve(_source, _args, _context, info) {
const { trackPromise } = info.getAsyncHelpers();
trackPromise(cleanupAfterResponse());
return 'ok';
}
```1 parent 3fe6d3f commit fcf5a8a
File tree
9 files changed
+474
-0
lines changed- src
- execution
- __tests__
9 files changed
+474
-0
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
33 | 41 | | |
34 | 42 | | |
35 | 43 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
61 | 61 | | |
62 | 62 | | |
63 | 63 | | |
| 64 | + | |
| 65 | + | |
64 | 66 | | |
65 | 67 | | |
66 | 68 | | |
| |||
116 | 118 | | |
117 | 119 | | |
118 | 120 | | |
| 121 | + | |
119 | 122 | | |
120 | 123 | | |
121 | 124 | | |
| |||
367 | 370 | | |
368 | 371 | | |
369 | 372 | | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
370 | 380 | | |
371 | 381 | | |
372 | 382 | | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
373 | 390 | | |
374 | 391 | | |
375 | 392 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
144 | 144 | | |
145 | 145 | | |
146 | 146 | | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
147 | 249 | | |
0 commit comments