|
1 | | -import { createHook, executionAsyncId } from 'async_hooks'; |
| 1 | +import { AsyncLocalStorage } from 'async_hooks'; |
2 | 2 |
|
3 | | -export interface ExecutionContextPicker { |
4 | | - getModuleContext(moduleId: string): GraphQLModules.ModuleContext; |
5 | | - getApplicationContext(): GraphQLModules.AppContext; |
6 | | -} |
| 3 | +/* |
| 4 | + Use AsyncLocalStorage if available (available sync Node 14). |
| 5 | + Otherwise, fall back to using async_hooks.createHook |
| 6 | +*/ |
7 | 7 |
|
8 | | -const executionContextStore = new Map<number, ExecutionContextPicker>(); |
9 | | -const executionContextDependencyStore = new Map<number, Set<number>>(); |
| 8 | +import * as Hooks from './execution-context-hooks'; |
| 9 | +import * as Async from './execution-context-async-local-storage'; |
10 | 10 |
|
11 | | -const executionContextHook = createHook({ |
12 | | - init(asyncId, _, triggerAsyncId) { |
13 | | - // Store same context data for child async resources |
14 | | - const ctx = executionContextStore.get(triggerAsyncId); |
15 | | - if (ctx) { |
16 | | - const dependencies = |
17 | | - executionContextDependencyStore.get(triggerAsyncId) ?? |
18 | | - executionContextDependencyStore |
19 | | - .set(triggerAsyncId, new Set()) |
20 | | - .get(triggerAsyncId)!; |
21 | | - dependencies.add(asyncId); |
22 | | - executionContextStore.set(asyncId, ctx); |
23 | | - } |
24 | | - }, |
25 | | - destroy(asyncId) { |
26 | | - if (executionContextStore.has(asyncId)) { |
27 | | - executionContextStore.delete(asyncId); |
28 | | - } |
29 | | - }, |
30 | | -}); |
| 11 | +export type { ExecutionContextPicker } from './execution-context.interface'; |
31 | 12 |
|
32 | | -function destroyContextAndItsChildren(id: number) { |
33 | | - if (executionContextStore.has(id)) { |
34 | | - executionContextStore.delete(id); |
35 | | - } |
| 13 | +export const executionContext = AsyncLocalStorage |
| 14 | + ? Async.executionContext |
| 15 | + : Hooks.executionContext; |
36 | 16 |
|
37 | | - const deps = executionContextDependencyStore.get(id); |
38 | | - |
39 | | - if (deps) { |
40 | | - for (const dep of deps) { |
41 | | - destroyContextAndItsChildren(dep); |
42 | | - } |
43 | | - executionContextDependencyStore.delete(id); |
44 | | - } |
45 | | -} |
46 | | - |
47 | | -export const executionContext: { |
48 | | - create(picker: ExecutionContextPicker): () => void; |
49 | | - getModuleContext: ExecutionContextPicker['getModuleContext']; |
50 | | - getApplicationContext: ExecutionContextPicker['getApplicationContext']; |
51 | | -} = { |
52 | | - create(picker) { |
53 | | - const id = executionAsyncId(); |
54 | | - executionContextStore.set(id, picker); |
55 | | - return function destroyContext() { |
56 | | - destroyContextAndItsChildren(id); |
57 | | - }; |
58 | | - }, |
59 | | - getModuleContext(moduleId) { |
60 | | - const picker = executionContextStore.get(executionAsyncId())!; |
61 | | - return picker.getModuleContext(moduleId); |
62 | | - }, |
63 | | - getApplicationContext() { |
64 | | - const picker = executionContextStore.get(executionAsyncId())!; |
65 | | - return picker.getApplicationContext(); |
66 | | - }, |
67 | | -}; |
68 | | - |
69 | | -let executionContextEnabled = false; |
70 | | - |
71 | | -export function enableExecutionContext() { |
72 | | - if (!executionContextEnabled) { |
73 | | - executionContextHook.enable(); |
74 | | - } |
75 | | -} |
76 | | - |
77 | | -export function getExecutionContextStore() { |
78 | | - return executionContextStore; |
79 | | -} |
80 | | - |
81 | | -export function getExecutionContextDependencyStore() { |
82 | | - return executionContextDependencyStore; |
83 | | -} |
| 17 | +export const enableExecutionContext = AsyncLocalStorage |
| 18 | + ? () => undefined |
| 19 | + : Hooks.enableExecutionContext; |
0 commit comments