Skip to content

Commit f71fc90

Browse files
puzpuzpuzcodebytere
authored andcommittedFeb 27, 2020
async_hooks: add store arg in AsyncLocalStorage
This commit introduces store as the first argument in AsyncLocalStorage's run methods. The change is motivated by the following expectation: most users are going to use a custom object as the store and an extra Map created by the previous implementation is an overhead for their use case. Important note. This is a backwards incompatible change. It was discussed and agreed an incompatible change is ok since the API is still experimental and the modified methods were only added within the last week so usage will be minimal to none. PR-URL: #31930 Reviewed-By: Stephen Belanger <admin@stephenbelanger.com> Reviewed-By: Vladimir de Turckheim <vlad2t@hotmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
1 parent 3497370 commit f71fc90

14 files changed

+73
-47
lines changed
 

‎benchmark/async_hooks/async-resource-vs-destroy.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ function buildDestroy(getServe) {
106106
function buildAsyncLocalStorage(getServe) {
107107
const asyncLocalStorage = new AsyncLocalStorage();
108108
const server = createServer((req, res) => {
109-
asyncLocalStorage.runSyncAndReturn(() => {
109+
asyncLocalStorage.runSyncAndReturn({}, () => {
110110
getServe(getCLS, setCLS)(req, res);
111111
});
112112
});
@@ -118,12 +118,12 @@ function buildAsyncLocalStorage(getServe) {
118118

119119
function getCLS() {
120120
const store = asyncLocalStorage.getStore();
121-
return store.get('store');
121+
return store.state;
122122
}
123123

124124
function setCLS(state) {
125125
const store = asyncLocalStorage.getStore();
126-
store.set('store', state);
126+
store.state = state;
127127
}
128128

129129
function close() {

‎doc/api/async_hooks.md

+25-21
Original file line numberDiff line numberDiff line change
@@ -893,7 +893,7 @@ function log(...args) {
893893
}
894894

895895
http.createServer((request, response) => {
896-
asyncLocalStorage.run(() => {
896+
asyncLocalStorage.run(new Map(), () => {
897897
const store = asyncLocalStorage.getStore();
898898
store.set(kReq, request);
899899
someAsyncOperation((err, result) => {
@@ -943,27 +943,27 @@ in the current process.
943943
added: REPLACEME
944944
-->
945945

946-
* Returns: {Map}
946+
* Returns: {any}
947947

948948
This method returns the current store.
949949
If this method is called outside of an asynchronous context initialized by
950950
calling `asyncLocalStorage.run` or `asyncLocalStorage.runAndReturn`, it will
951951
return `undefined`.
952952

953-
### `asyncLocalStorage.run(callback[, ...args])`
953+
### `asyncLocalStorage.run(store, callback[, ...args])`
954954
<!-- YAML
955955
added: REPLACEME
956956
-->
957957

958+
* `store` {any}
958959
* `callback` {Function}
959960
* `...args` {any}
960961

961962
Calling `asyncLocalStorage.run(callback)` will create a new asynchronous
962-
context.
963-
Within the callback function and the asynchronous operations from the callback,
964-
`asyncLocalStorage.getStore()` will return an instance of `Map` known as
965-
"the store". This store will be persistent through the following
966-
asynchronous calls.
963+
context. Within the callback function and the asynchronous operations from
964+
the callback, `asyncLocalStorage.getStore()` will return the object or
965+
the primitive value passed into the `store` argument (known as "the store").
966+
This store will be persistent through the following asynchronous calls.
967967

968968
The callback will be ran asynchronously. Optionally, arguments can be passed
969969
to the function. They will be passed to the callback function.
@@ -975,10 +975,11 @@ Also, the stacktrace will be impacted by the asynchronous call.
975975
Example:
976976

977977
```js
978-
asyncLocalStorage.run(() => {
979-
asyncLocalStorage.getStore(); // Returns a Map
978+
const store = { id: 1 };
979+
asyncLocalStorage.run(store, () => {
980+
asyncLocalStorage.getStore(); // Returns the store object
980981
someAsyncOperation(() => {
981-
asyncLocalStorage.getStore(); // Returns the same Map
982+
asyncLocalStorage.getStore(); // Returns the same object
982983
});
983984
});
984985
asyncLocalStorage.getStore(); // Returns undefined
@@ -1007,20 +1008,21 @@ Also, the stacktrace will be impacted by the asynchronous call.
10071008
Example:
10081009

10091010
```js
1010-
asyncLocalStorage.run(() => {
1011-
asyncLocalStorage.getStore(); // Returns a Map
1011+
asyncLocalStorage.run('store value', () => {
1012+
asyncLocalStorage.getStore(); // Returns 'store value'
10121013
asyncLocalStorage.exit(() => {
10131014
asyncLocalStorage.getStore(); // Returns undefined
10141015
});
1015-
asyncLocalStorage.getStore(); // Returns the same Map
1016+
asyncLocalStorage.getStore(); // Returns 'store value'
10161017
});
10171018
```
10181019

1019-
### `asyncLocalStorage.runSyncAndReturn(callback[, ...args])`
1020+
### `asyncLocalStorage.runSyncAndReturn(store, callback[, ...args])`
10201021
<!-- YAML
10211022
added: REPLACEME
10221023
-->
10231024

1025+
* `store` {any}
10241026
* `callback` {Function}
10251027
* `...args` {any}
10261028

@@ -1038,9 +1040,10 @@ the context will be exited.
10381040
Example:
10391041

10401042
```js
1043+
const store = { id: 2 };
10411044
try {
1042-
asyncLocalStorage.runSyncAndReturn(() => {
1043-
asyncLocalStorage.getStore(); // Returns a Map
1045+
asyncLocalStorage.runSyncAndReturn(store, () => {
1046+
asyncLocalStorage.getStore(); // Returns the store object
10441047
throw new Error();
10451048
});
10461049
} catch (e) {
@@ -1073,13 +1076,13 @@ Example:
10731076
```js
10741077
// Within a call to run or runSyncAndReturn
10751078
try {
1076-
asyncLocalStorage.getStore(); // Returns a Map
1079+
asyncLocalStorage.getStore(); // Returns the store object or value
10771080
asyncLocalStorage.exitSyncAndReturn(() => {
10781081
asyncLocalStorage.getStore(); // Returns undefined
10791082
throw new Error();
10801083
});
10811084
} catch (e) {
1082-
asyncLocalStorage.getStore(); // Returns the same Map
1085+
asyncLocalStorage.getStore(); // Returns the same object or value
10831086
// The error will be caught here
10841087
}
10851088
```
@@ -1105,8 +1108,9 @@ It cannot be promisified using `util.promisify`. If needed, the `Promise`
11051108
constructor can be used:
11061109

11071110
```js
1111+
const store = new Map(); // initialize the store
11081112
new Promise((resolve, reject) => {
1109-
asyncLocalStorage.run(() => {
1113+
asyncLocalStorage.run(store, () => {
11101114
someFunction((err, result) => {
11111115
if (err) {
11121116
return reject(err);
@@ -1135,7 +1139,7 @@ the following pattern should be used:
11351139

11361140
```js
11371141
async function fn() {
1138-
await asyncLocalStorage.runSyncAndReturn(() => {
1142+
await asyncLocalStorage.runSyncAndReturn(new Map(), () => {
11391143
asyncLocalStorage.getStore().set('key', value);
11401144
return foo(); // The return value of foo will be awaited
11411145
});

‎lib/async_hooks.js

+6-8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
'use strict';
22

33
const {
4-
Map,
54
NumberIsSafeInteger,
65
ReflectApply,
76
Symbol,
8-
97
} = primordials;
108

119
const {
@@ -247,14 +245,14 @@ class AsyncLocalStorage {
247245
}
248246
}
249247

250-
_enter() {
248+
_enter(store) {
251249
if (!this.enabled) {
252250
this.enabled = true;
253251
storageList.push(this);
254252
storageHook.enable();
255253
}
256254
const resource = executionAsyncResource();
257-
resource[this.kResourceStore] = new Map();
255+
resource[this.kResourceStore] = store;
258256
}
259257

260258
_exit() {
@@ -264,8 +262,8 @@ class AsyncLocalStorage {
264262
}
265263
}
266264

267-
runSyncAndReturn(callback, ...args) {
268-
this._enter();
265+
runSyncAndReturn(store, callback, ...args) {
266+
this._enter(store);
269267
try {
270268
return callback(...args);
271269
} finally {
@@ -289,8 +287,8 @@ class AsyncLocalStorage {
289287
}
290288
}
291289

292-
run(callback, ...args) {
293-
this._enter();
290+
run(store, callback, ...args) {
291+
this._enter(store);
294292
process.nextTick(callback, ...args);
295293
this._exit();
296294
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ const { AsyncLocalStorage } = require('async_hooks');
55

66
const asyncLocalStorage = new AsyncLocalStorage();
77

8-
asyncLocalStorage.run((runArg) => {
8+
asyncLocalStorage.run({}, (runArg) => {
99
assert.strictEqual(runArg, 1);
1010
asyncLocalStorage.exit((exitArg) => {
1111
assert.strictEqual(exitArg, 2);
1212
}, 2);
1313
}, 1);
1414

15-
asyncLocalStorage.runSyncAndReturn((runArg) => {
15+
asyncLocalStorage.runSyncAndReturn({}, (runArg) => {
1616
assert.strictEqual(runArg, 'foo');
1717
asyncLocalStorage.exitSyncAndReturn((exitArg) => {
1818
assert.strictEqual(exitArg, 'bar');

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ async function test() {
1212
}
1313

1414
async function main() {
15-
await asyncLocalStorage.runSyncAndReturn(test);
15+
await asyncLocalStorage.runSyncAndReturn(new Map(), test);
1616
assert.strictEqual(asyncLocalStorage.getStore(), undefined);
1717
}
1818

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ async function testAwait() {
1919
await asyncLocalStorage.exitSyncAndReturn(testOut);
2020
}
2121

22-
asyncLocalStorage.run(() => {
22+
asyncLocalStorage.run(new Map(), () => {
2323
const store = asyncLocalStorage.getStore();
2424
store.set('key', 'value');
2525
testAwait(); // should not reject

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ const { AsyncLocalStorage } = require('async_hooks');
55

66
const asyncLocalStorage = new AsyncLocalStorage();
77

8-
asyncLocalStorage.runSyncAndReturn(() => {
8+
asyncLocalStorage.runSyncAndReturn(new Map(), () => {
99
asyncLocalStorage.getStore().set('foo', 'bar');
1010
process.nextTick(() => {
1111
assert.strictEqual(asyncLocalStorage.getStore().get('foo'), 'bar');
1212
asyncLocalStorage.disable();
1313
assert.strictEqual(asyncLocalStorage.getStore(), undefined);
1414
process.nextTick(() => {
1515
assert.strictEqual(asyncLocalStorage.getStore(), undefined);
16-
asyncLocalStorage.runSyncAndReturn(() => {
16+
asyncLocalStorage.runSyncAndReturn(new Map(), () => {
1717
assert.notStrictEqual(asyncLocalStorage.getStore(), undefined);
1818
});
1919
});

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ process.setUncaughtExceptionCaptureCallback((err) => {
1313
assert.strictEqual(asyncLocalStorage.getStore().get('hello'), 'node');
1414
});
1515

16-
asyncLocalStorage.run(() => {
16+
asyncLocalStorage.run(new Map(), () => {
1717
const store = asyncLocalStorage.getStore();
1818
store.set('hello', 'node');
1919
setTimeout(() => {

‎test/async-hooks/test-async-local-storage-errors-sync-ret.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ process.setUncaughtExceptionCaptureCallback((err) => {
1414
});
1515

1616
try {
17-
asyncLocalStorage.runSyncAndReturn(() => {
17+
asyncLocalStorage.runSyncAndReturn(new Map(), () => {
1818
const store = asyncLocalStorage.getStore();
1919
store.set('hello', 'node');
2020
setTimeout(() => {

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const server = http.createServer((req, res) => {
1010
});
1111

1212
server.listen(0, () => {
13-
asyncLocalStorage.run(() => {
13+
asyncLocalStorage.run(new Map(), () => {
1414
const store = asyncLocalStorage.getStore();
1515
store.set('hello', 'world');
1616
http.get({ host: 'localhost', port: server.address().port }, () => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict';
2+
require('../common');
3+
const assert = require('assert');
4+
const { AsyncLocalStorage } = require('async_hooks');
5+
6+
const asyncLocalStorage = new AsyncLocalStorage();
7+
8+
asyncLocalStorage.run(42, () => {
9+
assert.strictEqual(asyncLocalStorage.getStore(), 42);
10+
});
11+
12+
const runStore = { foo: 'bar' };
13+
asyncLocalStorage.run(runStore, () => {
14+
assert.strictEqual(asyncLocalStorage.getStore(), runStore);
15+
});
16+
17+
asyncLocalStorage.runSyncAndReturn('hello node', () => {
18+
assert.strictEqual(asyncLocalStorage.getStore(), 'hello node');
19+
});
20+
21+
const runSyncStore = { hello: 'node' };
22+
asyncLocalStorage.runSyncAndReturn(runSyncStore, () => {
23+
assert.strictEqual(asyncLocalStorage.getStore(), runSyncStore);
24+
});

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ const { AsyncLocalStorage } = require('async_hooks');
66
const asyncLocalStorage = new AsyncLocalStorage();
77

88
setTimeout(() => {
9-
asyncLocalStorage.run(() => {
9+
asyncLocalStorage.run(new Map(), () => {
1010
const asyncLocalStorage2 = new AsyncLocalStorage();
11-
asyncLocalStorage2.run(() => {
11+
asyncLocalStorage2.run(new Map(), () => {
1212
const store = asyncLocalStorage.getStore();
1313
const store2 = asyncLocalStorage2.getStore();
1414
store.set('hello', 'world');

‎test/async-hooks/test-async-local-storage-no-mix-contexts.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ const asyncLocalStorage = new AsyncLocalStorage();
77
const asyncLocalStorage2 = new AsyncLocalStorage();
88

99
setTimeout(() => {
10-
asyncLocalStorage.run(() => {
11-
asyncLocalStorage2.run(() => {
10+
asyncLocalStorage.run(new Map(), () => {
11+
asyncLocalStorage2.run(new Map(), () => {
1212
const store = asyncLocalStorage.getStore();
1313
const store2 = asyncLocalStorage2.getStore();
1414
store.set('hello', 'world');
@@ -28,7 +28,7 @@ setTimeout(() => {
2828
}, 100);
2929

3030
setTimeout(() => {
31-
asyncLocalStorage.run(() => {
31+
asyncLocalStorage.run(new Map(), () => {
3232
const store = asyncLocalStorage.getStore();
3333
store.set('hello', 'earth');
3434
setTimeout(() => {

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ async function main() {
1212
throw err;
1313
});
1414
await new Promise((resolve, reject) => {
15-
asyncLocalStorage.run(() => {
15+
asyncLocalStorage.run(new Map(), () => {
1616
const store = asyncLocalStorage.getStore();
1717
store.set('a', 1);
1818
next().then(resolve, reject);

0 commit comments

Comments
 (0)
Please sign in to comment.