Skip to content

Commit 802b3e7

Browse files
committedMar 15, 2021
worker: add setEnvironmentData/getEnvironmentData
These APIs allow arbitrary, cloneable JavaScript values to be set and passed to all new Worker instances spawned from the current context. It is similar to `workerData` except that environment data is set independently of the `new Worker()` constructor, and the the value is passed automatically to all new Workers. This is a *partial* fix of nodejs#30992 but does not implement a complete fix. Signed-off-by: James M Snell <[email protected]> PR-URL: nodejs#37486 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Gireesh Punathil <[email protected]> Reviewed-By: Darshan Sen <[email protected]>
1 parent 7abdc3e commit 802b3e7

File tree

5 files changed

+114
-0
lines changed

5 files changed

+114
-0
lines changed
 

‎doc/api/worker_threads.md

+49
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,38 @@ Worker threads inherit non-process-specific options by default. Refer to
6161
[`Worker constructor options`][] to know how to customize worker thread options,
6262
specifically `argv` and `execArgv` options.
6363

64+
## `worker.getEnvironmentData(key)`
65+
<!-- YAML
66+
added: REPLACEME
67+
-->
68+
69+
> Stability: 1 - Experimental
70+
71+
* `key` {any} Any arbitrary, cloneable JavaScript value that can be used as a
72+
{Map} key.
73+
* Returns: {any}
74+
75+
Within a worker thread, `worker.getEnvironmentData()` returns a clone
76+
of data passed to the spawning thread's `worker.setEnvironmentData()`.
77+
Every new `Worker` receives its own copy of the environment data
78+
automatically.
79+
80+
```js
81+
const {
82+
Worker,
83+
isMainThread,
84+
setEnvironmentData,
85+
getEnvironmentData,
86+
} = require('worker_threads');
87+
88+
if (isMainThread) {
89+
setEnvironmentData('Hello', 'World!');
90+
const worker = new Worker(__filename);
91+
} else {
92+
console.log(getEnvironmentData('Hello')); // Prints 'World!'.
93+
}
94+
```
95+
6496
## `worker.isMainThread`
6597
<!-- YAML
6698
added: v10.5.0
@@ -246,6 +278,23 @@ new Worker('process.env.SET_IN_WORKER = "foo"', { eval: true, env: SHARE_ENV })
246278
});
247279
```
248280

281+
## `worker.setEnvironmentData(key[, value])`
282+
<!--YAML
283+
added: REPLACEME
284+
-->
285+
286+
> Stability: 1 - Experimental
287+
288+
* `key` {any} Any arbitrary, cloneable JavaScript value that can be used as a
289+
{Map} key.
290+
* `value` {any} Any arbitrary, cloneable JavaScript value that will be cloned
291+
and passed automatically to all new `Worker` instances. If `value` is passed
292+
as `undefined`, any previously set value for the `key` will be deleted.
293+
294+
The `worker.setEnvironmentData()` API sets the content of
295+
`worker.getEnvironmentData()` in the current thread and all new `Worker`
296+
instances spawned from the current context.
297+
249298
## `worker.threadId`
250299
<!-- YAML
251300
added: v10.5.0

‎lib/internal/main/worker_thread.js

+3
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ port.on('message', (message) => {
105105
filename,
106106
doEval,
107107
workerData,
108+
environmentData,
108109
publicPort,
109110
manifestSrc,
110111
manifestURL,
@@ -127,6 +128,8 @@ port.on('message', (message) => {
127128
publicWorker.parentPort = publicPort;
128129
publicWorker.workerData = workerData;
129130

131+
require('internal/worker').assignEnvironmentData(environmentData);
132+
130133
// The counter is only passed to the workers created by the main thread, not
131134
// to workers created by other workers.
132135
let cachedCwd = '';

‎lib/internal/worker.js

+25
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const {
1818
ReflectApply,
1919
RegExpPrototypeTest,
2020
SafeArrayIterator,
21+
SafeMap,
2122
String,
2223
Symbol,
2324
SymbolFor,
@@ -90,6 +91,8 @@ let debug = require('internal/util/debuglog').debuglog('worker', (fn) => {
9091

9192
let cwdCounter;
9293

94+
const environmentData = new SafeMap();
95+
9396
if (isMainThread) {
9497
cwdCounter = new Uint32Array(new SharedArrayBuffer(4));
9598
const originalChdir = process.chdir;
@@ -99,6 +102,24 @@ if (isMainThread) {
99102
};
100103
}
101104

105+
function setEnvironmentData(key, value) {
106+
if (value === undefined)
107+
environmentData.delete(key);
108+
else
109+
environmentData.set(key, value);
110+
}
111+
112+
function getEnvironmentData(key) {
113+
return environmentData.get(key);
114+
}
115+
116+
function assignEnvironmentData(data) {
117+
if (data === undefined) return;
118+
data.forEach((value, key) => {
119+
environmentData.set(key, value);
120+
});
121+
}
122+
102123
class Worker extends EventEmitter {
103124
constructor(filename, options = {}) {
104125
super();
@@ -228,6 +249,7 @@ class Worker extends EventEmitter {
228249
doEval,
229250
cwdCounter: cwdCounter || workerIo.sharedCwdCounter,
230251
workerData: options.workerData,
252+
environmentData,
231253
publicPort: port2,
232254
manifestURL: getOptionValue('--experimental-policy') ?
233255
require('internal/process/policy').url :
@@ -493,6 +515,9 @@ module.exports = {
493515
SHARE_ENV,
494516
resourceLimits:
495517
!isMainThread ? makeResourceLimits(resourceLimitsRaw) : {},
518+
setEnvironmentData,
519+
getEnvironmentData,
520+
assignEnvironmentData,
496521
threadId,
497522
Worker,
498523
};

‎lib/worker_threads.js

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ const {
44
isMainThread,
55
SHARE_ENV,
66
resourceLimits,
7+
setEnvironmentData,
8+
getEnvironmentData,
79
threadId,
810
Worker
911
} = require('internal/worker');
@@ -34,4 +36,6 @@ module.exports = {
3436
parentPort: null,
3537
workerData: null,
3638
BroadcastChannel,
39+
setEnvironmentData,
40+
getEnvironmentData,
3741
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict';
2+
3+
require('../common');
4+
const {
5+
Worker,
6+
getEnvironmentData,
7+
setEnvironmentData,
8+
threadId,
9+
} = require('worker_threads');
10+
11+
const {
12+
deepStrictEqual,
13+
strictEqual,
14+
} = require('assert');
15+
16+
if (!process.env.HAS_STARTED_WORKER) {
17+
process.env.HAS_STARTED_WORKER = 1;
18+
setEnvironmentData('foo', 'bar');
19+
setEnvironmentData('hello', { value: 'world' });
20+
setEnvironmentData(1, 2);
21+
strictEqual(getEnvironmentData(1), 2);
22+
setEnvironmentData(1); // Delete it, key won't show up in the worker.
23+
new Worker(__filename);
24+
setEnvironmentData('hello'); // Delete it. Has no impact on the worker.
25+
} else {
26+
strictEqual(getEnvironmentData('foo'), 'bar');
27+
deepStrictEqual(getEnvironmentData('hello'), { value: 'world' });
28+
strictEqual(getEnvironmentData(1), undefined);
29+
30+
// Recurse to make sure the environment data is inherited
31+
if (threadId <= 2)
32+
new Worker(__filename);
33+
}

0 commit comments

Comments
 (0)
Please sign in to comment.