jest-worker
Advanced tools
Comparing version 22.2.2 to 23.0.0-alpha.0
@@ -10,27 +10,25 @@ /** | ||
'use strict';var _types; | ||
'use strict'; | ||
function _load_types() {return _types = require('./types');} | ||
var _types; | ||
function _load_types() { | ||
return _types = require('./types'); | ||
} | ||
let file = null; | ||
/** | ||
* This file is a small bootstrapper for workers. It sets up the communication | ||
* between the worker and the parent process, interpreting parent messages and | ||
* sending results back. | ||
* | ||
* The file loaded will be lazily initialized the first time any of the workers | ||
* is called. This is done for optimal performance: if the farm is initialized, | ||
* but no call is made to it, child Node processes will be consuming the least | ||
* possible amount of memory. | ||
* | ||
* If an invalid message is detected, the child will exit (by throwing) with a | ||
* non-zero exit code. | ||
*/ | ||
* This file is a small bootstrapper for workers. It sets up the communication | ||
* between the worker and the parent process, interpreting parent messages and | ||
* sending results back. | ||
* | ||
* The file loaded will be lazily initialized the first time any of the workers | ||
* is called. This is done for optimal performance: if the farm is initialized, | ||
* but no call is made to it, child Node processes will be consuming the least | ||
* possible amount of memory. | ||
* | ||
* If an invalid message is detected, the child will exit (by throwing) with a | ||
* non-zero exit code. | ||
*/ | ||
process.on('message', (request /* Should be ChildMessage */) => { | ||
@@ -51,6 +49,4 @@ switch (request[0]) { | ||
default: | ||
throw new TypeError( | ||
'Unexpected request from parent process: ' + request[0]);} | ||
throw new TypeError('Unexpected request from parent process: ' + request[0]); | ||
} | ||
}); | ||
@@ -75,10 +71,5 @@ | ||
process.send([(_types || _load_types()).PARENT_MESSAGE_ERROR, | ||
error.constructor && error.constructor.name, | ||
error.message, | ||
error.stack, | ||
process.send([(_types || _load_types()).PARENT_MESSAGE_ERROR, error.constructor && error.constructor.name, error.message, error.stack, | ||
// $FlowFixMe: this is safe to just inherit from Object. | ||
typeof error === 'object' ? Object.assign({}, error) : error]); | ||
} | ||
@@ -85,0 +76,0 @@ |
@@ -10,52 +10,73 @@ /** | ||
'use strict';Object.defineProperty(exports, "__esModule", { value: true });var _mergeStream; | ||
'use strict'; | ||
function _load_mergeStream() {return _mergeStream = _interopRequireDefault(require('merge-stream'));}var _os; | ||
function _load_os() {return _os = _interopRequireDefault(require('os'));}var _path; | ||
function _load_path() {return _path = _interopRequireDefault(require('path'));}var _types; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
var _mergeStream; | ||
function _load_mergeStream() { | ||
return _mergeStream = _interopRequireDefault(require('merge-stream')); | ||
} | ||
var _os; | ||
function _load_types() {return _types = require('./types');}var _worker; | ||
function _load_worker() {return _worker = _interopRequireDefault(require('./worker'));}function _interopRequireDefault(obj) {return obj && obj.__esModule ? obj : { default: obj };} | ||
function _load_os() { | ||
return _os = _interopRequireDefault(require('os')); | ||
} | ||
/* istanbul ignore next */ | ||
const emptyMethod = () => {}; | ||
var _path; | ||
/** | ||
* The Jest farm (publicly called "Worker") is a class that allows you to queue | ||
* methods across multiple child processes, in order to parallelize work. This | ||
* is done by providing an absolute path to a module that will be loaded on each | ||
* of the child processes, and bridged to the main process. | ||
* | ||
* Bridged methods are specified by using the "exposedMethods" property of the | ||
* options "object". This is an array of strings, where each of them corresponds | ||
* to the exported name in the loaded module. | ||
* | ||
* You can also control the amount of workers by using the "numWorkers" property | ||
* of the "options" object, and the settings passed to fork the process through | ||
* the "forkOptions" property. The amount of workers defaults to the amount of | ||
* CPUS minus one. | ||
* | ||
* Queueing calls can be done in two ways: | ||
* - Standard method: calls will be redirected to the first available worker, | ||
* so they will get executed as soon as they can. | ||
* | ||
* - Sticky method: if a "computeWorkerKey" method is provided within the | ||
* config, the resulting string of this method will be used as a key. | ||
* Everytime this key is returned, it is guaranteed that your job will be | ||
* processed by the same worker. This is specially useful if your workers are | ||
* caching results. | ||
*/exports.default = | ||
class { | ||
function _load_path() { | ||
return _path = _interopRequireDefault(require('path')); | ||
} | ||
var _types; | ||
function _load_types() { | ||
return _types = require('./types'); | ||
} | ||
var _worker; | ||
function _load_worker() { | ||
return _worker = _interopRequireDefault(require('./worker')); | ||
} | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
/* istanbul ignore next */ | ||
const emptyMethod = () => {}; | ||
/** | ||
* The Jest farm (publicly called "Worker") is a class that allows you to queue | ||
* methods across multiple child processes, in order to parallelize work. This | ||
* is done by providing an absolute path to a module that will be loaded on each | ||
* of the child processes, and bridged to the main process. | ||
* | ||
* Bridged methods are specified by using the "exposedMethods" property of the | ||
* options "object". This is an array of strings, where each of them corresponds | ||
* to the exported name in the loaded module. | ||
* | ||
* You can also control the amount of workers by using the "numWorkers" property | ||
* of the "options" object, and the settings passed to fork the process through | ||
* the "forkOptions" property. The amount of workers defaults to the amount of | ||
* CPUS minus one. | ||
* | ||
* Queueing calls can be done in two ways: | ||
* - Standard method: calls will be redirected to the first available worker, | ||
* so they will get executed as soon as they can. | ||
* | ||
* - Sticky method: if a "computeWorkerKey" method is provided within the | ||
* config, the resulting string of this method will be used as a key. | ||
* Everytime this key is returned, it is guaranteed that your job will be | ||
* processed by the same worker. This is specially useful if your workers are | ||
* caching results. | ||
*/ | ||
exports.default = class { | ||
constructor(workerPath) {let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
constructor(workerPath) { | ||
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
const numWorkers = options.numWorkers || (_os || _load_os()).default.cpus().length - 1; | ||
@@ -73,9 +94,9 @@ const workers = new Array(numWorkers); | ||
maxRetries: options.maxRetries || 3, | ||
workerPath }; | ||
workerPath | ||
}; | ||
for (let i = 0; i < numWorkers; i++) { | ||
const workerOptions = Object.assign({}, sharedWorkerOptions, { | ||
workerId: i + 1 }); | ||
workerId: i + 1 | ||
}); | ||
const worker = new (_worker || _load_worker()).default(workerOptions); | ||
@@ -103,6 +124,4 @@ const workerStdout = worker.getStdout(); | ||
exposedMethods = Object.keys(child).filter( | ||
name => typeof child[name] === 'function'); | ||
exposedMethods = Object.keys(child).filter(name => typeof child[name] === 'function'); | ||
if (typeof child === 'function') { | ||
@@ -160,3 +179,7 @@ exposedMethods.push('default'); | ||
// eslint-disable-next-line no-unclear-flowtypes | ||
_makeCall(method) {for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {args[_key - 1] = arguments[_key];} | ||
_makeCall(method) { | ||
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | ||
args[_key - 1] = arguments[_key]; | ||
} | ||
if (this._ending) { | ||
@@ -166,4 +189,5 @@ throw new Error('Farm is ended, no more calls can be done to it'); | ||
return new Promise((resolve, reject) => {const | ||
computeWorkerKey = this._options.computeWorkerKey; | ||
return new Promise((resolve, reject) => { | ||
const computeWorkerKey = this._options.computeWorkerKey; | ||
const workers = this._workers; | ||
@@ -209,2 +233,3 @@ const length = workers.length; | ||
}); | ||
}}; | ||
} | ||
}; |
@@ -16,4 +16,7 @@ /** | ||
/* eslint-disable no-unclear-flowtypes */Object.defineProperty(exports, "__esModule", { value: true }); | ||
/* eslint-disable no-unclear-flowtypes */ | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
const CHILD_MESSAGE_INITIALIZE = exports.CHILD_MESSAGE_INITIALIZE = 0; | ||
@@ -28,70 +31,6 @@ const CHILD_MESSAGE_CALL = exports.CHILD_MESSAGE_CALL = 1; | ||
// Messages passed from the parent to the children. | ||
// Messages passed from the children to the parent. | ||
// Queue types. |
@@ -10,50 +10,45 @@ /** | ||
'use strict';Object.defineProperty(exports, "__esModule", { value: true });var _child_process; | ||
'use strict'; | ||
function _load_child_process() {return _child_process = _interopRequireDefault(require('child_process'));}var _types; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
function _load_types() {return _types = require('./types');}function _interopRequireDefault(obj) {return obj && obj.__esModule ? obj : { default: obj };} | ||
var _child_process; | ||
function _load_child_process() { | ||
return _child_process = _interopRequireDefault(require('child_process')); | ||
} | ||
var _types; | ||
function _load_types() { | ||
return _types = require('./types'); | ||
} | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
/** | ||
* This class wraps the child process and provides a nice interface to | ||
* communicate with. It takes care of: | ||
* | ||
* - Re-spawning the process if it dies. | ||
* - Queues calls while the worker is busy. | ||
* - Re-sends the requests if the worker blew up. | ||
* | ||
* The reason for queueing them here (since childProcess.send also has an | ||
* internal queue) is because the worker could be doing asynchronous work, and | ||
* this would lead to the child process to read its receiving buffer and start a | ||
* second call. By queueing calls here, we don't send the next call to the | ||
* children until we receive the result of the previous one. | ||
* | ||
* As soon as a request starts to be processed by a worker, its "processed" | ||
* field is changed to "true", so that other workers which might encounter the | ||
* same call skip it. | ||
*/exports.default = | ||
class { | ||
* This class wraps the child process and provides a nice interface to | ||
* communicate with. It takes care of: | ||
* | ||
* - Re-spawning the process if it dies. | ||
* - Queues calls while the worker is busy. | ||
* - Re-sends the requests if the worker blew up. | ||
* | ||
* The reason for queueing them here (since childProcess.send also has an | ||
* internal queue) is because the worker could be doing asynchronous work, and | ||
* this would lead to the child process to read its receiving buffer and start a | ||
* second call. By queueing calls here, we don't send the next call to the | ||
* children until we receive the result of the previous one. | ||
* | ||
* As soon as a request starts to be processed by a worker, its "processed" | ||
* field is changed to "true", so that other workers which might encounter the | ||
* same call skip it. | ||
*/ | ||
exports.default = class { | ||
constructor(options) { | ||
this._options = options; | ||
this._queue = []; | ||
this._queue = null; | ||
@@ -72,3 +67,11 @@ this._initialize(); | ||
send(request, callback) { | ||
this._queue.push({ callback, request }); | ||
const item = { callback, next: null, request }; | ||
if (this._last) { | ||
this._last.next = item; | ||
} else { | ||
this._queue = item; | ||
} | ||
this._last = item; | ||
this._process(); | ||
@@ -78,19 +81,14 @@ } | ||
_initialize() { | ||
const child = (_child_process || _load_child_process()).default.fork( | ||
require.resolve('./child'), | ||
const child = (_child_process || _load_child_process()).default.fork(require.resolve('./child'), | ||
// $FlowFixMe: Flow does not work well with Object.assign. | ||
Object.assign( | ||
{ | ||
Object.assign({ | ||
cwd: process.cwd(), | ||
env: Object.assign({}, process.env, { | ||
JEST_WORKER_ID: this._options.workerId }), | ||
// suppress --debug / --inspect flags while preserving others (like --harmony) | ||
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 }, | ||
silent: true | ||
}, this._options.forkOptions)); | ||
this._options.forkOptions)); | ||
child.on('message', this._receive.bind(this)); | ||
@@ -112,9 +110,3 @@ child.on('exit', this._exit.bind(this)); | ||
this._receive([(_types || _load_types()).PARENT_MESSAGE_ERROR, | ||
error.name, | ||
error.message, | ||
error.stack, | ||
{ type: 'WorkerError' }]); | ||
this._receive([(_types || _load_types()).PARENT_MESSAGE_ERROR, error.name, error.message, error.stack, { type: 'WorkerError' }]); | ||
} | ||
@@ -128,20 +120,16 @@ } | ||
const queue = this._queue; | ||
let skip = 0; | ||
let item = this._queue; | ||
// Calls in the queue might have already been processed by another worker, | ||
// so we have to skip them. | ||
while (queue.length > skip && queue[skip].request[1]) { | ||
skip++; | ||
while (item && item.request[1]) { | ||
item = item.next; | ||
} | ||
// Remove all pieces at once. | ||
queue.splice(0, skip); | ||
this._queue = item; | ||
if (queue.length) { | ||
const call = queue[0]; | ||
if (item) { | ||
// Flag the call as processed, so that other workers know that they don't | ||
// have to process it as well. | ||
call.request[1] = true; | ||
item.request[1] = true; | ||
@@ -152,3 +140,5 @@ this._retries = 0; | ||
// $FlowFixMe: wrong "ChildProcess.send" signature. | ||
this._child.send(call.request); | ||
this._child.send(item.request); | ||
} else { | ||
this._last = item; | ||
} | ||
@@ -158,4 +148,10 @@ } | ||
_receive(response /* Should be ParentMessage */) { | ||
const callback = this._queue[0].callback; | ||
const item = this._queue; | ||
if (!item) { | ||
throw new TypeError('Unexpected response with an empty queue'); | ||
} | ||
const callback = item.callback; | ||
this._busy = false; | ||
@@ -192,4 +188,4 @@ this._process(); | ||
default: | ||
throw new TypeError('Unexpected response from worker: ' + response[0]);} | ||
throw new TypeError('Unexpected response from worker: ' + response[0]); | ||
} | ||
} | ||
@@ -201,2 +197,3 @@ | ||
} | ||
}}; | ||
} | ||
}; |
{ | ||
"name": "jest-worker", | ||
"version": "22.2.2", | ||
"version": "23.0.0-alpha.0", | ||
"repository": { | ||
@@ -5,0 +5,0 @@ "type": "git", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
Unidentified License
License(Experimental) Something that seems like a license was found, but its contents could not be matched with a known license.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
431
22803
2
80
2