diff --git a/CHANGELOG.md b/CHANGELOG.md index 37b11d761972..8f43d93ac711 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ ## master +### Features + +* `[jest-worker]` Assign a unique id for each worker and pass it to the child + process. It will be available via `process.env.JEST_WORKER_ID` + ([#5494](https://github.com/facebook/jest/pull/5494)) + ## jest 22.2.1 ### Fixes diff --git a/packages/jest-worker/README.md b/packages/jest-worker/README.md index 2b4656f43169..cf4d08e41139 100644 --- a/packages/jest-worker/README.md +++ b/packages/jest-worker/README.md @@ -130,6 +130,9 @@ overriding options through `forkOptions`. Finishes the workers by killing all workers. No further calls can be done to the `Worker` instance. +**Note:** Each worker has a unique id (index that starts with `1`) which is +available on `process.env.JEST_WORKER_ID` + # More examples ## Standard usage @@ -143,12 +146,13 @@ import Worker from 'jest-worker'; async function main() { const myWorker = new Worker(require.resolve('./worker'), { - exposedMethods: ['foo', 'bar'], + exposedMethods: ['foo', 'bar', 'getWorkerId'], numWorkers: 4, }); console.log(await myWorker.foo('Alice')); // "Hello from foo: Alice" console.log(await myWorker.bar('Bob')); // "Hello from bar: Bob" + console.log(await myWorker.getWorkerId()); // "3" -> this message has sent from the 3rd worker myWorker.end(); } @@ -166,6 +170,10 @@ export function foo(param) { export function bar(param) { return 'Hello from bar: ' + param; } + +export function getWorkerId() { + return process.env.JEST_WORKER_ID; +} ``` ## Bound worker usage: diff --git a/packages/jest-worker/src/__tests__/index.test.js b/packages/jest-worker/src/__tests__/index.test.js index 7c9a422f09a6..927c14254270 100644 --- a/packages/jest-worker/src/__tests__/index.test.js +++ b/packages/jest-worker/src/__tests__/index.test.js @@ -122,10 +122,26 @@ it('tries instantiating workers with the right options', () => { expect(Worker.mock.calls[0][0]).toEqual({ forkOptions: {execArgv: []}, maxRetries: 6, + workerId: 1, workerPath: '/tmp/baz.js', }); }); +it('create multiple workers with unique worker ids', () => { + // eslint-disable-next-line no-new + new Farm('/tmp/baz.js', { + exposedMethods: ['foo', 'bar'], + forkOptions: {execArgv: []}, + maxRetries: 6, + numWorkers: 3, + }); + + expect(Worker).toHaveBeenCalledTimes(3); + expect(Worker.mock.calls[0][0].workerId).toEqual(1); + expect(Worker.mock.calls[1][0].workerId).toEqual(2); + expect(Worker.mock.calls[2][0].workerId).toEqual(3); +}); + it('makes a non-existing relative worker throw', () => { expect( () => diff --git a/packages/jest-worker/src/__tests__/worker.test.js b/packages/jest-worker/src/__tests__/worker.test.js index 4ab2d08aaee2..aacba5def4bf 100644 --- a/packages/jest-worker/src/__tests__/worker.test.js +++ b/packages/jest-worker/src/__tests__/worker.test.js @@ -57,6 +57,7 @@ it('passes fork options down to child_process.fork, adding the defaults', () => execPath: 'hello', }, maxRetries: 3, + workerId: process.env.JEST_WORKER_ID, workerPath: '/tmp/foo/bar/baz.js', }); @@ -70,6 +71,17 @@ it('passes fork options down to child_process.fork, adding the defaults', () => }); }); +it('passes workerId to the child process and assign it to env.JEST_WORKER_ID', () => { + new Worker({ + forkOptions: {}, + maxRetries: 3, + workerId: 2, + workerPath: '/tmp/foo', + }); + + expect(childProcess.fork.mock.calls[0][1].env.JEST_WORKER_ID).toEqual(2); +}); + it('initializes the child process with the given workerPath', () => { new Worker({ forkOptions: {}, diff --git a/packages/jest-worker/src/index.js b/packages/jest-worker/src/index.js index d0c49a054532..2193a4773009 100644 --- a/packages/jest-worker/src/index.js +++ b/packages/jest-worker/src/index.js @@ -66,14 +66,16 @@ export default class { workerPath = require.resolve(workerPath); } - // Build the options once for all workers to avoid allocating extra objects. - const workerOptions = { + const sharedWorkerOptions = { forkOptions: options.forkOptions || {}, maxRetries: options.maxRetries || 3, workerPath, }; for (let i = 0; i < numWorkers; i++) { + const workerOptions = Object.assign({}, sharedWorkerOptions, { + workerId: i + 1, + }); const worker = new Worker(workerOptions); const workerStdout = worker.getStdout(); const workerStderr = worker.getStderr(); diff --git a/packages/jest-worker/src/types.js b/packages/jest-worker/src/types.js index 1c0f2d5bd7c5..c40ed0e50e33 100644 --- a/packages/jest-worker/src/types.js +++ b/packages/jest-worker/src/types.js @@ -46,6 +46,7 @@ export type FarmOptions = { export type WorkerOptions = {| forkOptions: ForkOptions, maxRetries: number, + workerId: number, workerPath: string, |}; diff --git a/packages/jest-worker/src/worker.js b/packages/jest-worker/src/worker.js index ca7be4e3614c..e087ea05adec 100644 --- a/packages/jest-worker/src/worker.js +++ b/packages/jest-worker/src/worker.js @@ -79,7 +79,9 @@ export default class { Object.assign( { cwd: process.cwd(), - env: process.env, + env: Object.assign({}, process.env, { + JEST_WORKER_ID: this._options.workerId, + }), // suppress --debug / --inspect flags while preserving others (like --harmony) execArgv: process.execArgv.filter(v => !/^--(debug|inspect)/.test(v)), silent: true,