|
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