Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

worker: add support for platformData #37486

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions doc/api/worker_threads.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,38 @@ Worker threads inherit non-process-specific options by default. Refer to
[`Worker constructor options`][] to know how to customize worker thread options,
specifically `argv` and `execArgv` options.

## `worker.getEnvironmentData(key)`
<!-- YAML
added: REPLACEME
-->

> Stability: 1 - Experimental

* `key` {any} Any arbitrary, cloneable JavaScript value that can be used as a
{Map} key.
* Returns: {any}

Within a worker thread, `worker.getEnvironmentData()` returns a clone
of data passed to the spawning thread's `worker.setEnvironmentData()`.
Every new `Worker` receives its own copy of the environment data
automatically.

```js
const {
Worker,
isMainThread,
setEnvironmentData,
getEnvironmentData,
} = require('worker_threads');

if (isMainThread) {
setEnvironmentData('Hello', 'World!');
const worker = new Worker(__filename);
} else {
console.log(getEnvironmentData('Hello')); // Prints 'World!'.
}
```

## `worker.isMainThread`
<!-- YAML
added: v10.5.0
Expand Down Expand Up @@ -246,6 +278,23 @@ new Worker('process.env.SET_IN_WORKER = "foo"', { eval: true, env: SHARE_ENV })
});
```

## `worker.setEnvironmentData(key[, value])`
<!--YAML
added: REPLACEME
-->

> Stability: 1 - Experimental

* `key` {any} Any arbitrary, cloneable JavaScript value that can be used as a
{Map} key.
jasnell marked this conversation as resolved.
Show resolved Hide resolved
* `value` {any} Any arbitrary, cloneable JavaScript value that will be cloned
and passed automatically to all new `Worker` instances. If `value` is passed
as `undefined`, any previously set value for the `key` will be deleted.

The `worker.setEnvironmentData()` API sets the content of
`worker.getEnvironmentData()` in the current thread and all new `Worker`
instances spawned from the current context.

## `worker.threadId`
<!-- YAML
added: v10.5.0
Expand Down
3 changes: 3 additions & 0 deletions lib/internal/main/worker_thread.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ port.on('message', (message) => {
filename,
doEval,
workerData,
environmentData,
publicPort,
manifestSrc,
manifestURL,
Expand All @@ -127,6 +128,8 @@ port.on('message', (message) => {
publicWorker.parentPort = publicPort;
publicWorker.workerData = workerData;

require('internal/worker').assignEnvironmentData(environmentData);

// The counter is only passed to the workers created by the main thread, not
// to workers created by other workers.
let cachedCwd = '';
Expand Down
25 changes: 25 additions & 0 deletions lib/internal/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const {
ReflectApply,
RegExpPrototypeTest,
SafeArrayIterator,
SafeMap,
String,
Symbol,
SymbolFor,
Expand Down Expand Up @@ -90,6 +91,8 @@ let debug = require('internal/util/debuglog').debuglog('worker', (fn) => {

let cwdCounter;

const environmentData = new SafeMap();

if (isMainThread) {
cwdCounter = new Uint32Array(new SharedArrayBuffer(4));
const originalChdir = process.chdir;
Expand All @@ -99,6 +102,24 @@ if (isMainThread) {
};
}

function setEnvironmentData(key, value) {
if (value === undefined)
environmentData.delete(key);
else
environmentData.set(key, value);
}

function getEnvironmentData(key) {
return environmentData.get(key);
}

function assignEnvironmentData(data) {
if (data === undefined) return;
data.forEach((value, key) => {
environmentData.set(key, value);
});
}

class Worker extends EventEmitter {
constructor(filename, options = {}) {
super();
Expand Down Expand Up @@ -228,6 +249,7 @@ class Worker extends EventEmitter {
doEval,
cwdCounter: cwdCounter || workerIo.sharedCwdCounter,
workerData: options.workerData,
environmentData,
publicPort: port2,
manifestURL: getOptionValue('--experimental-policy') ?
require('internal/process/policy').url :
Expand Down Expand Up @@ -493,6 +515,9 @@ module.exports = {
SHARE_ENV,
resourceLimits:
!isMainThread ? makeResourceLimits(resourceLimitsRaw) : {},
setEnvironmentData,
getEnvironmentData,
assignEnvironmentData,
threadId,
Worker,
};
4 changes: 4 additions & 0 deletions lib/worker_threads.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const {
isMainThread,
SHARE_ENV,
resourceLimits,
setEnvironmentData,
getEnvironmentData,
threadId,
Worker
} = require('internal/worker');
Expand Down Expand Up @@ -34,4 +36,6 @@ module.exports = {
parentPort: null,
workerData: null,
BroadcastChannel,
setEnvironmentData,
getEnvironmentData,
};
33 changes: 33 additions & 0 deletions test/parallel/test-worker-environmentdata.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use strict';

require('../common');
const {
Worker,
getEnvironmentData,
setEnvironmentData,
threadId,
} = require('worker_threads');

const {
deepStrictEqual,
strictEqual,
} = require('assert');

if (!process.env.HAS_STARTED_WORKER) {
process.env.HAS_STARTED_WORKER = 1;
setEnvironmentData('foo', 'bar');
setEnvironmentData('hello', { value: 'world' });
setEnvironmentData(1, 2);
strictEqual(getEnvironmentData(1), 2);
setEnvironmentData(1); // Delete it, key won't show up in the worker.
new Worker(__filename);
setEnvironmentData('hello'); // Delete it. Has no impact on the worker.
} else {
strictEqual(getEnvironmentData('foo'), 'bar');
deepStrictEqual(getEnvironmentData('hello'), { value: 'world' });
strictEqual(getEnvironmentData(1), undefined);

// Recurse to make sure the environment data is inherited
if (threadId <= 2)
new Worker(__filename);
}