15
15
*/
16
16
17
17
import { ContextManager , Context } from '@opentelemetry/context-base' ;
18
- import * as asyncHooks from 'async_hooks' ;
18
+ import { AsyncLocalStorage } from 'async_hooks' ;
19
19
import { EventEmitter } from 'events' ;
20
20
21
21
type Func < T > = ( ...args : unknown [ ] ) => T ;
@@ -38,34 +38,21 @@ const ADD_LISTENER_METHODS = [
38
38
] ;
39
39
40
40
export class AsyncHooksContextManager implements ContextManager {
41
- private _asyncHook : asyncHooks . AsyncHook ;
42
- private _contexts : Map < number , Context | undefined > = new Map ( ) ;
43
- private _stack : Array < Context | undefined > = [ ] ;
41
+ private _asyncLocalStorage : AsyncLocalStorage < Context > ;
44
42
45
43
constructor ( ) {
46
- this . _asyncHook = asyncHooks . createHook ( {
47
- init : this . _init . bind ( this ) ,
48
- before : this . _before . bind ( this ) ,
49
- after : this . _after . bind ( this ) ,
50
- destroy : this . _destroy . bind ( this ) ,
51
- promiseResolve : this . _destroy . bind ( this ) ,
52
- } ) ;
44
+ this . _asyncLocalStorage = new AsyncLocalStorage ( ) ;
53
45
}
54
46
55
47
active ( ) : Context {
56
- return this . _stack [ this . _stack . length - 1 ] ?? Context . ROOT_CONTEXT ;
48
+ return this . _asyncLocalStorage . getStore ( ) ?? Context . ROOT_CONTEXT ;
57
49
}
58
50
59
51
with < T extends ( ...args : unknown [ ] ) => ReturnType < T > > (
60
52
context : Context ,
61
53
fn : T
62
54
) : ReturnType < T > {
63
- this . _enterContext ( context ) ;
64
- try {
65
- return fn ( ) ;
66
- } finally {
67
- this . _exitContext ( ) ;
68
- }
55
+ return this . _asyncLocalStorage . run ( context , fn ) as ReturnType < T > ;
69
56
}
70
57
71
58
bind < T > ( target : T , context ?: Context ) : T {
@@ -82,14 +69,11 @@ export class AsyncHooksContextManager implements ContextManager {
82
69
}
83
70
84
71
enable ( ) : this {
85
- this . _asyncHook . enable ( ) ;
86
72
return this ;
87
73
}
88
74
89
75
disable ( ) : this {
90
- this . _asyncHook . disable ( ) ;
91
- this . _contexts . clear ( ) ;
92
- this . _stack = [ ] ;
76
+ this . _asyncLocalStorage . disable ( ) ;
93
77
return this ;
94
78
}
95
79
@@ -217,57 +201,4 @@ export class AsyncHooksContextManager implements ContextManager {
217
201
return original . call ( this , event , patchedListener ) ;
218
202
} ;
219
203
}
220
-
221
- /**
222
- * Init hook will be called when userland create a async context, setting the
223
- * context as the current one if it exist.
224
- * @param uid id of the async context
225
- */
226
- private _init ( uid : number ) {
227
- const context = this . _stack [ this . _stack . length - 1 ] ;
228
- if ( context !== undefined ) {
229
- this . _contexts . set ( uid , context ) ;
230
- }
231
- }
232
-
233
- /**
234
- * Destroy hook will be called when a given context is no longer used so we can
235
- * remove its attached context.
236
- * @param uid uid of the async context
237
- */
238
- private _destroy ( uid : number ) {
239
- this . _contexts . delete ( uid ) ;
240
- }
241
-
242
- /**
243
- * Before hook is called just beforing executing a async context.
244
- * @param uid uid of the async context
245
- */
246
- private _before ( uid : number ) {
247
- const context = this . _contexts . get ( uid ) ;
248
- if ( context !== undefined ) {
249
- this . _enterContext ( context ) ;
250
- }
251
- }
252
-
253
- /**
254
- * After hook is called just after completing the execution of a async context.
255
- */
256
- private _after ( ) {
257
- this . _exitContext ( ) ;
258
- }
259
-
260
- /**
261
- * Set the given context as active
262
- */
263
- private _enterContext ( context : Context ) {
264
- this . _stack . push ( context ) ;
265
- }
266
-
267
- /**
268
- * Remove the context at the root of the stack
269
- */
270
- private _exitContext ( ) {
271
- this . _stack . pop ( ) ;
272
- }
273
204
}
0 commit comments