Skip to content

Commit 0dfd38d

Browse files
committed
feat(asynchooks): implement withAsync open-telemetry#752
1 parent e4d8323 commit 0dfd38d

File tree

2 files changed

+43
-19
lines changed

2 files changed

+43
-19
lines changed

packages/opentelemetry-context-async-hooks/src/AsyncHooksContextManager.ts

+42-15
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,19 @@ type PatchedEventEmitter = {
2929
__ot_listeners?: { [name: string]: WeakMap<Func<void>, Func<void>> };
3030
} & EventEmitter;
3131

32+
class Reference<T> {
33+
constructor(private _value: T) {}
34+
35+
set(value: T) {
36+
this._value = value;
37+
return this;
38+
}
39+
40+
get() {
41+
return this._value;
42+
}
43+
}
44+
3245
const ADD_LISTENER_METHODS = [
3346
'addListener' as 'addListener',
3447
'on' as 'on',
@@ -39,9 +52,7 @@ const ADD_LISTENER_METHODS = [
3952

4053
export class AsyncHooksContextManager implements ContextManager {
4154
private _asyncHook: asyncHooks.AsyncHook;
42-
private _contexts: {
43-
[uid: number]: Context | undefined | null;
44-
} = Object.create(null);
55+
private _contextRefs: Map<number, Reference<Context> | undefined> = new Map();
4556

4657
constructor() {
4758
this._asyncHook = asyncHooks.createHook({
@@ -52,18 +63,24 @@ export class AsyncHooksContextManager implements ContextManager {
5263
}
5364

5465
active(): Context {
55-
return (
56-
this._contexts[asyncHooks.executionAsyncId()] || Context.ROOT_CONTEXT
57-
);
66+
const ref = this._contextRefs.get(asyncHooks.executionAsyncId());
67+
return ref === undefined ? Context.ROOT_CONTEXT : ref.get();
5868
}
5969

6070
with<T extends (...args: unknown[]) => ReturnType<T>>(
6171
context: Context,
6272
fn: T
6373
): ReturnType<T> {
6474
const uid = asyncHooks.executionAsyncId();
65-
const oldContext = this._contexts[uid];
66-
this._contexts[uid] = context;
75+
let ref = this._contextRefs.get(uid);
76+
let oldContext: Context | undefined = undefined;
77+
if (ref === undefined) {
78+
ref = new Reference(context);
79+
this._contextRefs.set(uid, ref);
80+
} else {
81+
oldContext = ref.get();
82+
ref.set(context);
83+
}
6784
try {
6885
return fn();
6986
} catch (err) {
@@ -72,7 +89,7 @@ export class AsyncHooksContextManager implements ContextManager {
7289
if (oldContext === undefined) {
7390
this._destroy(uid);
7491
} else {
75-
this._contexts[uid] = oldContext;
92+
ref.set(oldContext);
7693
}
7794
}
7895
}
@@ -82,8 +99,15 @@ export class AsyncHooksContextManager implements ContextManager {
8299
fn: U
83100
): Promise<T> {
84101
const uid = asyncHooks.executionAsyncId();
85-
const oldContext = this._contexts[uid];
86-
this._contexts[uid] = context;
102+
let ref = this._contextRefs.get(uid);
103+
let oldContext: Context | undefined = undefined;
104+
if (ref === undefined) {
105+
ref = new Reference(context);
106+
this._contextRefs.set(uid, ref);
107+
} else {
108+
oldContext = ref.get();
109+
ref.set(context);
110+
}
87111
try {
88112
return await fn();
89113
} catch (err) {
@@ -92,7 +116,7 @@ export class AsyncHooksContextManager implements ContextManager {
92116
if (oldContext === undefined) {
93117
this._destroy(uid);
94118
} else {
95-
this._contexts[uid] = oldContext;
119+
ref.set(oldContext);
96120
}
97121
}
98122
}
@@ -117,7 +141,7 @@ export class AsyncHooksContextManager implements ContextManager {
117141

118142
disable(): this {
119143
this._asyncHook.disable();
120-
this._contexts = {};
144+
this._contextRefs.clear();
121145
return this;
122146
}
123147

@@ -252,7 +276,10 @@ export class AsyncHooksContextManager implements ContextManager {
252276
* @param uid id of the async context
253277
*/
254278
private _init(uid: number) {
255-
this._contexts[uid] = this._contexts[asyncHooks.executionAsyncId()];
279+
this._contextRefs.set(
280+
uid,
281+
this._contextRefs.get(asyncHooks.executionAsyncId())
282+
);
256283
}
257284

258285
/**
@@ -261,6 +288,6 @@ export class AsyncHooksContextManager implements ContextManager {
261288
* @param uid uid of the async context
262289
*/
263290
private _destroy(uid: number) {
264-
delete this._contexts[uid];
291+
this._contextRefs.delete(uid);
265292
}
266293
}

packages/opentelemetry-context-base/src/NoopContextManager.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@ export class NoopContextManager implements types.ContextManager {
2222
return Context.ROOT_CONTEXT;
2323
}
2424

25-
with(
26-
context: Context,
27-
fn: Function
28-
) {
25+
with(context: Context, fn: Function) {
2926
return fn();
3027
}
3128

0 commit comments

Comments
 (0)