Skip to content

Commit 3befe80

Browse files
puzpuzpuzMylesBorins
authored andcommitted
async_hooks: fix ctx loss after nested ALS calls
PR-URL: #32085 Reviewed-By: Stephen Belanger <[email protected]> Reviewed-By: Vladimir de Turckheim <[email protected]> Reviewed-By: Michael Dawson <[email protected]>
1 parent a037770 commit 3befe80

File tree

3 files changed

+50
-23
lines changed

3 files changed

+50
-23
lines changed

‎lib/async_hooks.js‎

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -255,23 +255,21 @@ class AsyncLocalStorage{
255255
resource[this.kResourceStore]=store;
256256
}
257257

258-
_exit(){
259-
constresource=executionAsyncResource();
260-
if(resource){
261-
resource[this.kResourceStore]=undefined;
262-
}
263-
}
264-
265258
runSyncAndReturn(store,callback, ...args){
259+
constresource=executionAsyncResource();
260+
constouterStore=resource[this.kResourceStore];
266261
this._enter(store);
267262
try{
268263
returncallback(...args);
269264
}finally{
270-
this._exit();
265+
resource[this.kResourceStore]=outerStore;
271266
}
272267
}
273268

274269
exitSyncAndReturn(callback, ...args){
270+
if(!this.enabled){
271+
returncallback(...args);
272+
}
275273
this.enabled=false;
276274
try{
277275
returncallback(...args);
@@ -288,12 +286,17 @@ class AsyncLocalStorage{
288286
}
289287

290288
run(store,callback, ...args){
289+
constresource=executionAsyncResource();
290+
constouterStore=resource[this.kResourceStore];
291291
this._enter(store);
292292
process.nextTick(callback, ...args);
293-
this._exit();
293+
resource[this.kResourceStore]=outerStore;
294294
}
295295

296296
exit(callback, ...args){
297+
if(!this.enabled){
298+
returnprocess.nextTick(callback, ...args);
299+
}
297300
this.enabled=false;
298301
process.nextTick(callback, ...args);
299302
this.enabled=true;

‎test/async-hooks/test-async-local-storage-enable-disable.js‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,16 @@ asyncLocalStorage.runSyncAndReturn(new Map(), () =>{
1212
process.nextTick(()=>{
1313
assert.strictEqual(asyncLocalStorage.getStore(),undefined);
1414
});
15+
1516
asyncLocalStorage.disable();
1617
assert.strictEqual(asyncLocalStorage.getStore(),undefined);
18+
19+
// Calls to exit() should not mess with enabled status
20+
asyncLocalStorage.exit(()=>{
21+
assert.strictEqual(asyncLocalStorage.getStore(),undefined);
22+
});
23+
assert.strictEqual(asyncLocalStorage.getStore(),undefined);
24+
1725
process.nextTick(()=>{
1826
assert.strictEqual(asyncLocalStorage.getStore(),undefined);
1927
asyncLocalStorage.runSyncAndReturn(newMap(),()=>{

‎test/async-hooks/test-async-local-storage-nested.js‎

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,35 @@ const assert = require('assert');
44
const{ AsyncLocalStorage }=require('async_hooks');
55

66
constasyncLocalStorage=newAsyncLocalStorage();
7+
constouter={};
8+
constinner={};
79

8-
setTimeout(()=>{
9-
asyncLocalStorage.run(newMap(),()=>{
10-
constasyncLocalStorage2=newAsyncLocalStorage();
11-
asyncLocalStorage2.run(newMap(),()=>{
12-
conststore=asyncLocalStorage.getStore();
13-
conststore2=asyncLocalStorage2.getStore();
14-
store.set('hello','world');
15-
store2.set('hello','foo');
16-
setTimeout(()=>{
17-
assert.strictEqual(asyncLocalStorage.getStore().get('hello'),'world');
18-
assert.strictEqual(asyncLocalStorage2.getStore().get('hello'),'foo');
19-
},200);
20-
});
10+
functiontestInner(){
11+
assert.strictEqual(asyncLocalStorage.getStore(),outer);
12+
13+
asyncLocalStorage.run(inner,()=>{
14+
assert.strictEqual(asyncLocalStorage.getStore(),inner);
15+
});
16+
assert.strictEqual(asyncLocalStorage.getStore(),outer);
17+
18+
asyncLocalStorage.exit(()=>{
19+
assert.strictEqual(asyncLocalStorage.getStore(),undefined);
20+
});
21+
assert.strictEqual(asyncLocalStorage.getStore(),outer);
22+
23+
asyncLocalStorage.runSyncAndReturn(inner,()=>{
24+
assert.strictEqual(asyncLocalStorage.getStore(),inner);
2125
});
22-
},100);
26+
assert.strictEqual(asyncLocalStorage.getStore(),outer);
27+
28+
asyncLocalStorage.exitSyncAndReturn(()=>{
29+
assert.strictEqual(asyncLocalStorage.getStore(),undefined);
30+
});
31+
assert.strictEqual(asyncLocalStorage.getStore(),outer);
32+
}
33+
34+
asyncLocalStorage.run(outer,testInner);
35+
assert.strictEqual(asyncLocalStorage.getStore(),undefined);
36+
37+
asyncLocalStorage.runSyncAndReturn(outer,testInner);
38+
assert.strictEqual(asyncLocalStorage.getStore(),undefined);

0 commit comments

Comments
(0)