jest-worker
Advanced tools
Comparing version 29.1.2 to 29.2.0
@@ -7,19 +7,13 @@ 'use strict'; | ||
exports.default = void 0; | ||
function _mergeStream() { | ||
const data = _interopRequireDefault(require('merge-stream')); | ||
_mergeStream = function () { | ||
return data; | ||
}; | ||
return data; | ||
} | ||
var _types = require('../types'); | ||
function _interopRequireDefault(obj) { | ||
return obj && obj.__esModule ? obj : {default: obj}; | ||
} | ||
/** | ||
@@ -31,10 +25,10 @@ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | ||
*/ | ||
// How long to wait for the child process to terminate | ||
// after CHILD_MESSAGE_END before sending force exiting. | ||
const FORCE_EXIT_DELAY = 500; | ||
/* istanbul ignore next */ | ||
// eslint-disable-next-line @typescript-eslint/no-empty-function | ||
const emptyMethod = () => {}; | ||
class BaseWorkerPool { | ||
@@ -45,3 +39,2 @@ _stderr; | ||
_workers; | ||
constructor(workerPath, options) { | ||
@@ -53,3 +46,2 @@ this._options = options; | ||
const {forkOptions, maxRetries, resourceLimits, setupArgs} = options; | ||
for (let i = 0; i < options.numWorkers; i++) { | ||
@@ -68,38 +60,28 @@ const workerOptions = { | ||
const workerStderr = worker.getStderr(); | ||
if (workerStdout) { | ||
stdout.add(workerStdout); | ||
} | ||
if (workerStderr) { | ||
stderr.add(workerStderr); | ||
} | ||
this._workers[i] = worker; | ||
} | ||
this._stdout = stdout; | ||
this._stderr = stderr; | ||
} | ||
getStderr() { | ||
return this._stderr; | ||
} | ||
getStdout() { | ||
return this._stdout; | ||
} | ||
getWorkers() { | ||
return this._workers; | ||
} | ||
getWorkerById(workerId) { | ||
return this._workers[workerId]; | ||
} | ||
createWorker(_workerOptions) { | ||
throw Error('Missing method createWorker in WorkerPool'); | ||
} | ||
async end() { | ||
@@ -114,5 +96,6 @@ // We do not cache the request object here. If so, it would only be only | ||
emptyMethod | ||
); // Schedule a force exit in case worker fails to exit gracefully so | ||
); | ||
// Schedule a force exit in case worker fails to exit gracefully so | ||
// await worker.waitForExit() never takes longer than FORCE_EXIT_DELAY | ||
let forceExited = false; | ||
@@ -123,8 +106,7 @@ const forceExitTimeout = setTimeout(() => { | ||
}, FORCE_EXIT_DELAY); | ||
await worker.waitForExit(); // Worker ideally exited gracefully, don't send force exit then | ||
await worker.waitForExit(); | ||
// Worker ideally exited gracefully, don't send force exit then | ||
clearTimeout(forceExitTimeout); | ||
return forceExited; | ||
}); | ||
const workerExits = await Promise.all(workerExitPromises); | ||
@@ -141,3 +123,2 @@ return workerExits.reduce( | ||
} | ||
exports.default = BaseWorkerPool; |
@@ -7,11 +7,7 @@ 'use strict'; | ||
exports.default = void 0; | ||
var _FifoQueue = _interopRequireDefault(require('./FifoQueue')); | ||
var _types = require('./types'); | ||
function _interopRequireDefault(obj) { | ||
return obj && obj.__esModule ? obj : {default: obj}; | ||
} | ||
/** | ||
@@ -23,2 +19,3 @@ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | ||
*/ | ||
class Farm { | ||
@@ -31,3 +28,2 @@ _computeWorkerKey; | ||
_taskQueue; | ||
constructor(_numOfWorkers, _callback, options = {}) { | ||
@@ -41,6 +37,4 @@ this._numOfWorkers = _numOfWorkers; | ||
} | ||
doWork(method, ...args) { | ||
const customMessageListeners = new Set(); | ||
const addCustomMessageListener = listener => { | ||
@@ -52,8 +46,7 @@ customMessageListeners.add(listener); | ||
}; | ||
const onCustomMessage = message => { | ||
customMessageListeners.forEach(listener => listener(message)); | ||
}; | ||
const promise = new Promise( // Bind args to this function so it won't reference to the parent scope. | ||
const promise = new Promise( | ||
// Bind args to this function so it won't reference to the parent scope. | ||
// This prevents a memory leak in v8, because otherwise the function will | ||
@@ -66,3 +59,2 @@ // retain args for the closure. | ||
let hash = null; | ||
if (computeWorkerKey) { | ||
@@ -72,3 +64,2 @@ hash = computeWorkerKey.call(this, method, ...args); | ||
} | ||
const onStart = worker => { | ||
@@ -79,6 +70,4 @@ if (hash != null) { | ||
}; | ||
const onEnd = (error, result) => { | ||
customMessageListeners.clear(); | ||
if (error) { | ||
@@ -90,3 +79,2 @@ reject(error); | ||
}; | ||
const task = { | ||
@@ -98,6 +86,4 @@ onCustomMessage, | ||
}; | ||
if (worker) { | ||
this._taskQueue.enqueue(task, worker.getWorkerId()); | ||
this._process(worker.getWorkerId()); | ||
@@ -112,3 +98,2 @@ } else { | ||
} | ||
_process(workerId) { | ||
@@ -118,17 +103,14 @@ if (this._isLocked(workerId)) { | ||
} | ||
const task = this._taskQueue.dequeue(workerId); | ||
if (!task) { | ||
return this; | ||
} | ||
if (task.request[1]) { | ||
throw new Error('Queue implementation returned processed task'); | ||
} // Reference the task object outside so it won't be retained by onEnd, | ||
} | ||
// Reference the task object outside so it won't be retained by onEnd, | ||
// and other properties of the task object, such as task.request can be | ||
// garbage collected. | ||
let taskOnEnd = task.onEnd; | ||
const onEnd = (error, result) => { | ||
@@ -138,14 +120,8 @@ if (taskOnEnd) { | ||
} | ||
taskOnEnd = null; | ||
this._unlock(workerId); | ||
this._process(workerId); | ||
}; | ||
task.request[1] = true; | ||
this._lock(workerId); | ||
this._callback( | ||
@@ -158,14 +134,9 @@ workerId, | ||
); | ||
return this; | ||
} | ||
_push(task) { | ||
this._taskQueue.enqueue(task); | ||
const offset = this._getNextWorkerOffset(); | ||
for (let i = 0; i < this._numOfWorkers; i++) { | ||
this._process((offset + i) % this._numOfWorkers); | ||
if (task.request[1]) { | ||
@@ -175,6 +146,4 @@ break; | ||
} | ||
return this; | ||
} | ||
_getNextWorkerOffset() { | ||
@@ -184,3 +153,2 @@ switch (this._workerSchedulingPolicy) { | ||
return 0; | ||
case 'round-robin': | ||
@@ -190,11 +158,8 @@ return this._offset++; | ||
} | ||
_lock(workerId) { | ||
this._locks[workerId] = true; | ||
} | ||
_unlock(workerId) { | ||
this._locks[workerId] = false; | ||
} | ||
_isLocked(workerId) { | ||
@@ -204,3 +169,2 @@ return this._locks[workerId]; | ||
} | ||
exports.default = Farm; |
@@ -7,3 +7,2 @@ 'use strict'; | ||
exports.default = void 0; | ||
/** | ||
@@ -24,18 +23,12 @@ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | ||
_sharedQueue = new InternalQueue(); | ||
enqueue(task, workerId) { | ||
if (workerId == null) { | ||
this._sharedQueue.enqueue(task); | ||
return; | ||
} | ||
let workerQueue = this._workerQueues[workerId]; | ||
if (workerQueue == null) { | ||
workerQueue = this._workerQueues[workerId] = new InternalQueue(); | ||
} | ||
const sharedTop = this._sharedQueue.peekLast(); | ||
const item = { | ||
@@ -47,21 +40,18 @@ previousSharedTask: sharedTop, | ||
} | ||
dequeue(workerId) { | ||
const workerTop = this._workerQueues[workerId]?.peek(); | ||
const sharedTaskIsProcessed = | ||
workerTop?.previousSharedTask?.request[1] ?? true; // Process the top task from the shared queue if | ||
workerTop?.previousSharedTask?.request[1] ?? true; | ||
// Process the top task from the shared queue if | ||
// - there's no task in the worker specific queue or | ||
// - if the non-worker-specific task after which this worker specific task | ||
// has been queued wasn't processed yet | ||
if (workerTop != null && sharedTaskIsProcessed) { | ||
return this._workerQueues[workerId]?.dequeue()?.task ?? null; | ||
} | ||
return this._sharedQueue.dequeue(); | ||
} | ||
} | ||
exports.default = FifoQueue; | ||
/** | ||
@@ -73,3 +63,2 @@ * FIFO queue for a single worker / shared queue. | ||
_last = null; | ||
enqueue(value) { | ||
@@ -80,3 +69,2 @@ const item = { | ||
}; | ||
if (this._last == null) { | ||
@@ -87,6 +75,4 @@ this._head = item; | ||
} | ||
this._last = item; | ||
} | ||
dequeue() { | ||
@@ -96,17 +82,12 @@ if (this._head == null) { | ||
} | ||
const item = this._head; | ||
this._head = item.next; | ||
if (this._head == null) { | ||
this._last = null; | ||
} | ||
return item.value; | ||
} | ||
peek() { | ||
return this._head?.value ?? null; | ||
} | ||
peekLast() { | ||
@@ -113,0 +94,0 @@ return this._last?.value ?? null; |
@@ -9,3 +9,2 @@ /** | ||
import type {EventEmitter} from 'events'; | ||
import type {ForkOptions} from 'child_process'; | ||
@@ -29,21 +28,22 @@ import type {ResourceLimits} from 'worker_threads'; | ||
declare type ChildMessageCall = [ | ||
typeof CHILD_MESSAGE_CALL, | ||
boolean, | ||
string, | ||
Array<unknown>, | ||
type: typeof CHILD_MESSAGE_CALL, | ||
isProcessed: boolean, | ||
methodName: string, | ||
args: Array<unknown>, | ||
]; | ||
declare type ChildMessageEnd = [typeof CHILD_MESSAGE_END, boolean]; | ||
declare type ChildMessageEnd = [ | ||
type: typeof CHILD_MESSAGE_END, | ||
isProcessed: boolean, | ||
]; | ||
declare type ChildMessageInitialize = [ | ||
typeof CHILD_MESSAGE_INITIALIZE, | ||
boolean, | ||
string, | ||
// file | ||
Array<unknown> | undefined, | ||
// setupArgs | ||
MessagePort_2 | undefined, | ||
type: typeof CHILD_MESSAGE_INITIALIZE, | ||
isProcessed: boolean, | ||
fileName: string, | ||
setupArgs: Array<unknown>, | ||
workerId: string | undefined, | ||
]; | ||
declare type ChildMessageMemUsage = [typeof CHILD_MESSAGE_MEM_USAGE]; | ||
declare type ChildMessageMemUsage = [type: typeof CHILD_MESSAGE_MEM_USAGE]; | ||
@@ -64,3 +64,3 @@ declare type ComputeTaskPriorityCallback = ( | ||
private _workerQueues; | ||
private _sharedQueue; | ||
private readonly _sharedQueue; | ||
enqueue(task: QueueChildMessage, workerId?: number): void; | ||
@@ -84,6 +84,2 @@ dequeue(workerId: number): QueueChildMessage | null; | ||
declare type MessagePort_2 = typeof EventEmitter & { | ||
postMessage(message: unknown): void; | ||
}; | ||
declare type MethodLikeKeys<T> = { | ||
@@ -94,3 +90,3 @@ [K in keyof T]: T[K] extends FunctionLike ? K : never; | ||
declare class MinHeap<TItem extends HeapItem> { | ||
private _heap; | ||
private readonly _heap; | ||
peek(): TItem | null; | ||
@@ -126,5 +122,5 @@ add(item: TItem): void; | ||
export declare class PriorityQueue implements TaskQueue { | ||
private _computePriority; | ||
private readonly _computePriority; | ||
private _queue; | ||
private _sharedQueue; | ||
private readonly _sharedQueue; | ||
constructor(_computePriority: ComputeTaskPriorityCallback); | ||
@@ -209,5 +205,5 @@ enqueue(task: QueueChildMessage, workerId?: number): void; | ||
private _ending; | ||
private _farm; | ||
private _options; | ||
private _workerPool; | ||
private readonly _farm; | ||
private readonly _options; | ||
private readonly _workerPool; | ||
constructor(workerPath: string, options?: WorkerFarmOptions); | ||
@@ -214,0 +210,0 @@ private _bindExposedWorkerMethods; |
@@ -25,37 +25,24 @@ 'use strict'; | ||
}); | ||
function _os() { | ||
const data = require('os'); | ||
_os = function () { | ||
return data; | ||
}; | ||
return data; | ||
} | ||
function _path() { | ||
const data = require('path'); | ||
_path = function () { | ||
return data; | ||
}; | ||
return data; | ||
} | ||
var _Farm = _interopRequireDefault(require('./Farm')); | ||
var _WorkerPool = _interopRequireDefault(require('./WorkerPool')); | ||
var _PriorityQueue = _interopRequireDefault(require('./PriorityQueue')); | ||
var _FifoQueue = _interopRequireDefault(require('./FifoQueue')); | ||
var _messageParent = _interopRequireDefault(require('./workers/messageParent')); | ||
function _interopRequireDefault(obj) { | ||
return obj && obj.__esModule ? obj : {default: obj}; | ||
} | ||
/** | ||
@@ -67,12 +54,12 @@ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | ||
*/ | ||
function getExposedMethods(workerPath, options) { | ||
let exposedMethods = options.exposedMethods; // If no methods list is given, try getting it by auto-requiring the module. | ||
let exposedMethods = options.exposedMethods; | ||
// If no methods list is given, try getting it by auto-requiring the module. | ||
if (!exposedMethods) { | ||
const module = require(workerPath); | ||
exposedMethods = Object.keys(module).filter( | ||
name => typeof module[name] === 'function' | ||
); | ||
if (typeof module === 'function') { | ||
@@ -82,5 +69,5 @@ exposedMethods = [...exposedMethods, 'default']; | ||
} | ||
return exposedMethods; | ||
} | ||
/** | ||
@@ -111,3 +98,2 @@ * The Jest farm (publicly called "Worker") is a class that allows you to queue | ||
*/ | ||
class Worker { | ||
@@ -118,11 +104,10 @@ _ending; | ||
_workerPool; | ||
constructor(workerPath, options) { | ||
this._options = {...options}; | ||
this._options = { | ||
...options | ||
}; | ||
this._ending = false; | ||
if (!(0, _path().isAbsolute)(workerPath)) { | ||
throw new Error(`'workerPath' must be absolute, got '${workerPath}'`); | ||
} | ||
const workerPoolOptions = { | ||
@@ -138,3 +123,2 @@ enableWorkerThreads: this._options.enableWorkerThreads ?? false, | ||
}; | ||
if (this._options.WorkerPool) { | ||
@@ -148,3 +132,2 @@ this._workerPool = new this._options.WorkerPool( | ||
} | ||
this._farm = new _Farm.default( | ||
@@ -159,6 +142,4 @@ workerPoolOptions.numWorkers, | ||
); | ||
this._bindExposedWorkerMethods(workerPath, this._options); | ||
} | ||
_bindExposedWorkerMethods(workerPath, options) { | ||
@@ -168,12 +149,13 @@ getExposedMethods(workerPath, options).forEach(name => { | ||
return; | ||
} // eslint-disable-next-line no-prototype-builtins | ||
} | ||
// eslint-disable-next-line no-prototype-builtins | ||
if (this.constructor.prototype.hasOwnProperty(name)) { | ||
throw new TypeError(`Cannot define a method called ${name}`); | ||
} // @ts-expect-error: dynamic extension of the class instance is expected. | ||
} | ||
// @ts-expect-error: dynamic extension of the class instance is expected. | ||
this[name] = this._callFunctionWithArgs.bind(this, name); | ||
}); | ||
} | ||
_callFunctionWithArgs(method, ...args) { | ||
@@ -183,14 +165,10 @@ if (this._ending) { | ||
} | ||
return this._farm.doWork(method, ...args); | ||
} | ||
getStderr() { | ||
return this._workerPool.getStderr(); | ||
} | ||
getStdout() { | ||
return this._workerPool.getStdout(); | ||
} | ||
async end() { | ||
@@ -200,3 +178,2 @@ if (this._ending) { | ||
} | ||
this._ending = true; | ||
@@ -206,3 +183,2 @@ return this._workerPool.end(); | ||
} | ||
exports.Worker = Worker; |
@@ -7,3 +7,2 @@ 'use strict'; | ||
exports.default = void 0; | ||
/** | ||
@@ -28,7 +27,5 @@ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | ||
_sharedQueue = new MinHeap(); | ||
constructor(_computePriority) { | ||
this._computePriority = _computePriority; | ||
} | ||
enqueue(task, workerId) { | ||
@@ -39,7 +36,5 @@ if (workerId == null) { | ||
const queue = this._getWorkerQueue(workerId); | ||
this._enqueue(task, queue); | ||
} | ||
} | ||
_enqueue(task, queue) { | ||
@@ -52,9 +47,8 @@ const item = { | ||
} | ||
dequeue(workerId) { | ||
const workerQueue = this._getWorkerQueue(workerId); | ||
const workerTop = workerQueue.peek(); | ||
const sharedTop = this._sharedQueue.peek(); | ||
const sharedTop = this._sharedQueue.peek(); // use the task from the worker queue if there's no task in the shared queue | ||
// use the task from the worker queue if there's no task in the shared queue | ||
// or if the priority of the worker queue is smaller or equal to the | ||
@@ -64,3 +58,2 @@ // priority of the top task in the shared queue. The tasks of the | ||
// specific task up. | ||
if ( | ||
@@ -72,44 +65,33 @@ sharedTop == null || | ||
} | ||
return this._sharedQueue.poll().task; | ||
} | ||
_getWorkerQueue(workerId) { | ||
let queue = this._queue[workerId]; | ||
if (queue == null) { | ||
queue = this._queue[workerId] = new MinHeap(); | ||
} | ||
return queue; | ||
} | ||
} | ||
exports.default = PriorityQueue; | ||
class MinHeap { | ||
_heap = []; | ||
peek() { | ||
return this._heap[0] ?? null; | ||
} | ||
add(item) { | ||
const nodes = this._heap; | ||
nodes.push(item); | ||
if (nodes.length === 1) { | ||
return; | ||
} | ||
let currentIndex = nodes.length - 1; | ||
let currentIndex = nodes.length - 1; // Bubble up the added node as long as the parent is bigger | ||
// Bubble up the added node as long as the parent is bigger | ||
while (currentIndex > 0) { | ||
const parentIndex = Math.floor((currentIndex + 1) / 2) - 1; | ||
const parent = nodes[parentIndex]; | ||
if (parent.priority <= item.priority) { | ||
break; | ||
} | ||
nodes[currentIndex] = parent; | ||
@@ -120,16 +102,14 @@ nodes[parentIndex] = item; | ||
} | ||
poll() { | ||
const nodes = this._heap; | ||
const result = nodes[0]; | ||
const lastElement = nodes.pop(); // heap was empty or removed the last element | ||
const lastElement = nodes.pop(); | ||
// heap was empty or removed the last element | ||
if (result == null || nodes.length === 0) { | ||
return result ?? null; | ||
} | ||
let index = 0; | ||
nodes[0] = lastElement ?? null; | ||
const element = nodes[0]; | ||
while (true) { | ||
@@ -140,9 +120,11 @@ let swapIndex = null; | ||
const rightChild = nodes[rightChildIndex]; | ||
const leftChild = nodes[leftChildIndex]; // if the left child is smaller, swap with the left | ||
const leftChild = nodes[leftChildIndex]; | ||
// if the left child is smaller, swap with the left | ||
if (leftChild != null && leftChild.priority < element.priority) { | ||
swapIndex = leftChildIndex; | ||
} // If the right child is smaller or the right child is smaller than the left | ||
} | ||
// If the right child is smaller or the right child is smaller than the left | ||
// then swap with the right child | ||
if ( | ||
@@ -154,7 +136,5 @@ rightChild != null && | ||
} | ||
if (swapIndex == null) { | ||
break; | ||
} | ||
nodes[index] = nodes[swapIndex]; | ||
@@ -164,5 +144,4 @@ nodes[swapIndex] = element; | ||
} | ||
return result; | ||
} | ||
} |
@@ -18,3 +18,2 @@ 'use strict'; | ||
void 0; | ||
/** | ||
@@ -26,5 +25,7 @@ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | ||
*/ | ||
// Because of the dynamic nature of a worker communication process, all messages | ||
// coming from any of the other processes cannot be typed. Thus, many types | ||
// include "unknown" as a TS type, which is (unfortunately) correct here. | ||
const CHILD_MESSAGE_INITIALIZE = 0; | ||
@@ -50,3 +51,2 @@ exports.CHILD_MESSAGE_INITIALIZE = CHILD_MESSAGE_INITIALIZE; | ||
exports.WorkerStates = WorkerStates; | ||
(function (WorkerStates) { | ||
@@ -60,8 +60,6 @@ WorkerStates['STARTING'] = 'starting'; | ||
})(WorkerStates || (exports.WorkerStates = WorkerStates = {})); | ||
let WorkerEvents; | ||
exports.WorkerEvents = WorkerEvents; | ||
(function (WorkerEvents) { | ||
WorkerEvents['STATE_CHANGE'] = 'state-change'; | ||
})(WorkerEvents || (exports.WorkerEvents = WorkerEvents = {})); |
@@ -7,9 +7,6 @@ 'use strict'; | ||
exports.default = void 0; | ||
var _BaseWorkerPool = _interopRequireDefault(require('./base/BaseWorkerPool')); | ||
function _interopRequireDefault(obj) { | ||
return obj && obj.__esModule ? obj : {default: obj}; | ||
} | ||
/** | ||
@@ -21,2 +18,3 @@ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | ||
*/ | ||
class WorkerPool extends _BaseWorkerPool.default { | ||
@@ -26,6 +24,4 @@ send(workerId, request, onStart, onEnd, onCustomMessage) { | ||
} | ||
createWorker(workerOptions) { | ||
let Worker; | ||
if (this._options.enableWorkerThreads) { | ||
@@ -36,8 +32,6 @@ Worker = require('./workers/NodeThreadsWorker').default; | ||
} | ||
return new Worker(workerOptions); | ||
} | ||
} | ||
var _default = WorkerPool; | ||
exports.default = _default; |
@@ -7,51 +7,35 @@ 'use strict'; | ||
exports.default = exports.SIGKILL_DELAY = void 0; | ||
function _child_process() { | ||
const data = require('child_process'); | ||
_child_process = function () { | ||
return data; | ||
}; | ||
return data; | ||
} | ||
function _os() { | ||
const data = require('os'); | ||
_os = function () { | ||
return data; | ||
}; | ||
return data; | ||
} | ||
function _mergeStream() { | ||
const data = _interopRequireDefault(require('merge-stream')); | ||
_mergeStream = function () { | ||
return data; | ||
}; | ||
return data; | ||
} | ||
function _supportsColor() { | ||
const data = require('supports-color'); | ||
_supportsColor = function () { | ||
return data; | ||
}; | ||
return data; | ||
} | ||
var _types = require('../types'); | ||
var _WorkerAbstract = _interopRequireDefault(require('./WorkerAbstract')); | ||
function _interopRequireDefault(obj) { | ||
return obj && obj.__esModule ? obj : {default: obj}; | ||
} | ||
/** | ||
@@ -63,7 +47,10 @@ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | ||
*/ | ||
const SIGNAL_BASE_EXIT_CODE = 128; | ||
const SIGKILL_EXIT_CODE = SIGNAL_BASE_EXIT_CODE + 9; | ||
const SIGTERM_EXIT_CODE = SIGNAL_BASE_EXIT_CODE + 15; // How long to wait after SIGTERM before sending SIGKILL | ||
const SIGTERM_EXIT_CODE = SIGNAL_BASE_EXIT_CODE + 15; | ||
// How long to wait after SIGTERM before sending SIGKILL | ||
const SIGKILL_DELAY = 500; | ||
/** | ||
@@ -87,5 +74,3 @@ * This class wraps the child process and provides a nice interface to | ||
*/ | ||
exports.SIGKILL_DELAY = SIGKILL_DELAY; | ||
class ChildProcessWorker extends _WorkerAbstract.default { | ||
@@ -107,3 +92,2 @@ _child; | ||
_childWorkerPath; | ||
constructor(options) { | ||
@@ -122,3 +106,2 @@ super(options); | ||
} | ||
initialize() { | ||
@@ -132,7 +115,5 @@ if ( | ||
} | ||
if (this._child && this._child.connected) { | ||
this._child.kill('SIGKILL'); | ||
} | ||
this.state = _types.WorkerStates.STARTING; | ||
@@ -145,3 +126,2 @@ const forceColor = _supportsColor().stdout | ||
const silent = this._options.silent ?? true; | ||
if (!silent) { | ||
@@ -155,3 +135,2 @@ // NOTE: Detecting an out of memory crash is independent of idle memory usage monitoring. We want to | ||
} | ||
this._stderrBuffer = []; | ||
@@ -178,3 +157,2 @@ const options = { | ||
); | ||
if (this._child.stdout) { | ||
@@ -186,6 +164,4 @@ if (!this._stdout) { | ||
} | ||
this._stdout.add(this._child.stdout); | ||
} | ||
if (this._child.stderr) { | ||
@@ -197,14 +173,8 @@ if (!this._stderr) { | ||
} | ||
this._stderr.add(this._child.stderr); | ||
this._child.stderr.on('data', this.stderrDataHandler.bind(this)); | ||
} | ||
this._child.on('message', this._onMessage.bind(this)); | ||
this._child.on('exit', this._onExit.bind(this)); | ||
this._child.on('disconnect', this._onDisconnect.bind(this)); | ||
this._child.send([ | ||
@@ -216,7 +186,7 @@ _types.CHILD_MESSAGE_INITIALIZE, | ||
]); | ||
this._retries++; | ||
this._retries++; // If we exceeded the amount of retries, we will emulate an error reply | ||
// If we exceeded the amount of retries, we will emulate an error reply | ||
// coming from the child. This avoids code duplication related with cleaning | ||
// the queue, and scheduling the next call. | ||
if (this._retries > this._options.maxRetries) { | ||
@@ -226,3 +196,2 @@ const error = new Error( | ||
); | ||
this._onMessage([ | ||
@@ -236,9 +205,8 @@ _types.PARENT_MESSAGE_CLIENT_ERROR, | ||
} | ||
]); // Clear the request so we don't keep executing it. | ||
]); | ||
// Clear the request so we don't keep executing it. | ||
this._request = null; | ||
} | ||
this.state = _types.WorkerStates.OK; | ||
if (this._resolveWorkerReady) { | ||
@@ -248,3 +216,2 @@ this._resolveWorkerReady(); | ||
} | ||
stderrDataHandler(chunk) { | ||
@@ -254,5 +221,3 @@ if (chunk) { | ||
} | ||
this._detectOutOfMemoryCrash(); | ||
if (this.state === _types.WorkerStates.OUT_OF_MEMORY) { | ||
@@ -262,11 +227,8 @@ this._workerReadyPromise = undefined; | ||
this.killChild(); | ||
this._shutdown(); | ||
} | ||
} | ||
_detectOutOfMemoryCrash() { | ||
try { | ||
const bufferStr = Buffer.concat(this._stderrBuffer).toString('utf8'); | ||
if ( | ||
@@ -288,32 +250,23 @@ bufferStr.includes('heap out of memory') || | ||
} | ||
_onDisconnect() { | ||
this._workerReadyPromise = undefined; | ||
this._resolveWorkerReady = undefined; | ||
this._detectOutOfMemoryCrash(); | ||
if (this.state === _types.WorkerStates.OUT_OF_MEMORY) { | ||
this.killChild(); | ||
this._shutdown(); | ||
} | ||
} | ||
_onMessage(response) { | ||
// TODO: Add appropriate type check | ||
let error; | ||
switch (response[0]) { | ||
case _types.PARENT_MESSAGE_OK: | ||
this._onProcessEnd(null, response[1]); | ||
break; | ||
case _types.PARENT_MESSAGE_CLIENT_ERROR: | ||
error = response[4]; | ||
if (error != null && typeof error === 'object') { | ||
const extra = error; // @ts-expect-error: no index | ||
const extra = error; | ||
// @ts-expect-error: no index | ||
const NativeCtor = globalThis[response[1]]; | ||
@@ -324,3 +277,2 @@ const Ctor = typeof NativeCtor === 'function' ? NativeCtor : Error; | ||
error.stack = response[3]; | ||
for (const key in extra) { | ||
@@ -330,7 +282,4 @@ error[key] = extra[key]; | ||
} | ||
this._onProcessEnd(error, null); | ||
break; | ||
case _types.PARENT_MESSAGE_SETUP_ERROR: | ||
@@ -340,26 +289,16 @@ error = new Error(`Error when calling setup: ${response[2]}`); | ||
error.stack = response[3]; | ||
this._onProcessEnd(error, null); | ||
break; | ||
case _types.PARENT_MESSAGE_CUSTOM: | ||
this._onCustomMessage(response[1]); | ||
break; | ||
case _types.PARENT_MESSAGE_MEM_USAGE: | ||
this._childIdleMemoryUsage = response[1]; | ||
if (this._resolveMemoryUsage) { | ||
this._resolveMemoryUsage(response[1]); | ||
this._resolveMemoryUsage = undefined; | ||
this._memoryUsagePromise = undefined; | ||
} | ||
this._performRestartIfRequired(); | ||
break; | ||
default: | ||
@@ -369,11 +308,11 @@ throw new TypeError(`Unexpected response from worker: ${response[0]}`); | ||
} | ||
_performRestartIfRequired() { | ||
if (this._memoryUsageCheck) { | ||
this._memoryUsageCheck = false; | ||
let limit = this._childIdleMemoryUsageLimit; // TODO: At some point it would make sense to make use of | ||
let limit = this._childIdleMemoryUsageLimit; | ||
// TODO: At some point it would make sense to make use of | ||
// stringToBytes found in jest-config, however as this | ||
// package does not have any dependencies on an other jest | ||
// packages that can wait until some other time. | ||
if (limit && limit > 0 && limit <= 1) { | ||
@@ -384,3 +323,2 @@ limit = Math.floor((0, _os().totalmem)() * limit); | ||
} | ||
if ( | ||
@@ -396,9 +334,6 @@ limit && | ||
} | ||
_onExit(exitCode) { | ||
this._workerReadyPromise = undefined; | ||
this._resolveWorkerReady = undefined; | ||
this._detectOutOfMemoryCrash(); | ||
if (exitCode !== 0 && this.state === _types.WorkerStates.OUT_OF_MEMORY) { | ||
@@ -409,3 +344,2 @@ this._onProcessEnd( | ||
); | ||
this._shutdown(); | ||
@@ -422,3 +356,2 @@ } else if ( | ||
this.initialize(); | ||
if (this._request) { | ||
@@ -431,13 +364,11 @@ this._child.send(this._request); | ||
} | ||
send(request, onProcessStart, onProcessEnd, onCustomMessage) { | ||
this._stderrBuffer = []; | ||
onProcessStart(this); | ||
this._onProcessEnd = (...args) => { | ||
const hasRequest = !!this._request; | ||
this._onProcessEnd = (...args) => { | ||
const hasRequest = !!this._request; // Clean the request to avoid sending past requests to workers that fail | ||
// Clean the request to avoid sending past requests to workers that fail | ||
// while waiting for a new request (timers, unhandled rejections...) | ||
this._request = null; | ||
if ( | ||
@@ -450,18 +381,13 @@ this._childIdleMemoryUsageLimit && | ||
} | ||
return onProcessEnd(...args); | ||
}; | ||
this._onCustomMessage = (...arg) => onCustomMessage(...arg); | ||
this._request = request; | ||
this._retries = 0; // eslint-disable-next-line @typescript-eslint/no-empty-function | ||
this._retries = 0; | ||
// eslint-disable-next-line @typescript-eslint/no-empty-function | ||
this._child.send(request, () => {}); | ||
} | ||
waitForExit() { | ||
return this._exitPromise; | ||
} | ||
killChild() { | ||
@@ -474,13 +400,11 @@ // We store a reference so that there's no way we can accidentally | ||
} | ||
forceExit() { | ||
this.state = _types.WorkerStates.SHUTTING_DOWN; | ||
const sigkillTimeout = this.killChild(); | ||
this._exitPromise.then(() => clearTimeout(sigkillTimeout)); | ||
} | ||
getWorkerId() { | ||
return this._options.workerId; | ||
} | ||
/** | ||
@@ -491,14 +415,12 @@ * Gets the process id of the worker. | ||
*/ | ||
getWorkerSystemId() { | ||
return this._child.pid; | ||
} | ||
getStdout() { | ||
return this._stdout; | ||
} | ||
getStderr() { | ||
return this._stderr; | ||
} | ||
/** | ||
@@ -509,3 +431,2 @@ * Gets the last reported memory usage. | ||
*/ | ||
getMemoryUsage() { | ||
@@ -519,3 +440,2 @@ if (!this._memoryUsagePromise) { | ||
this._memoryUsagePromise = promise; | ||
if (!this._child.connected && rejectCallback) { | ||
@@ -527,3 +447,2 @@ rejectCallback(new Error('Child process is not running.')); | ||
} | ||
this._child.send([_types.CHILD_MESSAGE_MEM_USAGE], err => { | ||
@@ -536,16 +455,13 @@ if (err && rejectCallback) { | ||
}); | ||
return promise; | ||
} | ||
return this._memoryUsagePromise; | ||
} | ||
/** | ||
* Gets updated memory usage and restarts if required | ||
*/ | ||
checkMemoryUsage() { | ||
if (this._childIdleMemoryUsageLimit) { | ||
this._memoryUsageCheck = true; | ||
this._child.send([_types.CHILD_MESSAGE_MEM_USAGE], err => { | ||
@@ -562,3 +478,2 @@ if (err) { | ||
} | ||
isWorkerRunning() { | ||
@@ -568,3 +483,2 @@ return this._child.connected && !this._child.killed; | ||
} | ||
exports.default = ChildProcessWorker; |
@@ -7,15 +7,10 @@ 'use strict'; | ||
exports.default = messageParent; | ||
function _worker_threads() { | ||
const data = require('worker_threads'); | ||
_worker_threads = function () { | ||
return data; | ||
}; | ||
return data; | ||
} | ||
var _types = require('../types'); | ||
/** | ||
@@ -27,2 +22,3 @@ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | ||
*/ | ||
function messageParent(message, parentProcess = process) { | ||
@@ -29,0 +25,0 @@ if (!_worker_threads().isMainThread && _worker_threads().parentPort != null) { |
@@ -7,41 +7,28 @@ 'use strict'; | ||
exports.default = void 0; | ||
function _os() { | ||
const data = require('os'); | ||
_os = function () { | ||
return data; | ||
}; | ||
return data; | ||
} | ||
function _worker_threads() { | ||
const data = require('worker_threads'); | ||
_worker_threads = function () { | ||
return data; | ||
}; | ||
return data; | ||
} | ||
function _mergeStream() { | ||
const data = _interopRequireDefault(require('merge-stream')); | ||
_mergeStream = function () { | ||
return data; | ||
}; | ||
return data; | ||
} | ||
var _types = require('../types'); | ||
var _WorkerAbstract = _interopRequireDefault(require('./WorkerAbstract')); | ||
function _interopRequireDefault(obj) { | ||
return obj && obj.__esModule ? obj : {default: obj}; | ||
} | ||
/** | ||
@@ -53,2 +40,3 @@ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | ||
*/ | ||
class ExperimentalWorker extends _WorkerAbstract.default { | ||
@@ -69,3 +57,2 @@ _worker; | ||
_memoryUsageCheck = false; | ||
constructor(options) { | ||
@@ -83,3 +70,2 @@ super(options); | ||
} | ||
initialize() { | ||
@@ -93,7 +79,5 @@ if ( | ||
} | ||
if (this._worker) { | ||
this._worker.terminate(); | ||
} | ||
this.state = _types.WorkerStates.STARTING; | ||
@@ -108,3 +92,2 @@ this._worker = new (_worker_threads().Worker)(this._childWorkerPath, { | ||
}); | ||
if (this._worker.stdout) { | ||
@@ -116,6 +99,4 @@ if (!this._stdout) { | ||
} | ||
this._stdout.add(this._worker.stdout); | ||
} | ||
if (this._worker.stderr) { | ||
@@ -127,22 +108,16 @@ if (!this._stderr) { | ||
} | ||
this._stderr.add(this._worker.stderr); | ||
} // This can be useful for debugging. | ||
} | ||
// This can be useful for debugging. | ||
if (!(this._options.silent ?? true)) { | ||
this._worker.stdout.setEncoding('utf8'); // eslint-disable-next-line no-console | ||
this._worker.stdout.setEncoding('utf8'); | ||
// eslint-disable-next-line no-console | ||
this._worker.stdout.on('data', console.log); | ||
this._worker.stderr.setEncoding('utf8'); | ||
this._worker.stderr.on('data', console.error); | ||
} | ||
this._worker.on('message', this._onMessage.bind(this)); | ||
this._worker.on('exit', this._onExit.bind(this)); | ||
this._worker.on('error', this._onError.bind(this)); | ||
this._worker.postMessage([ | ||
@@ -156,9 +131,9 @@ _types.CHILD_MESSAGE_INITIALIZE, | ||
this._retries++; // If we exceeded the amount of retries, we will emulate an error reply | ||
this._retries++; | ||
// If we exceeded the amount of retries, we will emulate an error reply | ||
// coming from the child. This avoids code duplication related with cleaning | ||
// the queue, and scheduling the next call. | ||
if (this._retries > this._options.maxRetries) { | ||
const error = new Error('Call retries were exceeded'); | ||
this._onMessage([ | ||
@@ -174,5 +149,3 @@ _types.PARENT_MESSAGE_CLIENT_ERROR, | ||
} | ||
this.state = _types.WorkerStates.OK; | ||
if (this._resolveWorkerReady) { | ||
@@ -182,28 +155,23 @@ this._resolveWorkerReady(); | ||
} | ||
_onError(error) { | ||
if (error.message.includes('heap out of memory')) { | ||
this.state = _types.WorkerStates.OUT_OF_MEMORY; // Threads don't behave like processes, they don't crash when they run out of | ||
this.state = _types.WorkerStates.OUT_OF_MEMORY; | ||
// Threads don't behave like processes, they don't crash when they run out of | ||
// memory. But for consistency we want them to behave like processes so we call | ||
// terminate to simulate a crash happening that was not planned | ||
this._worker.terminate(); | ||
} | ||
} | ||
_onMessage(response) { | ||
let error; | ||
switch (response[0]) { | ||
case _types.PARENT_MESSAGE_OK: | ||
this._onProcessEnd(null, response[1]); | ||
break; | ||
case _types.PARENT_MESSAGE_CLIENT_ERROR: | ||
error = response[4]; | ||
if (error != null && typeof error === 'object') { | ||
const extra = error; // @ts-expect-error: no index | ||
const extra = error; | ||
// @ts-expect-error: no index | ||
const NativeCtor = globalThis[response[1]]; | ||
@@ -214,3 +182,2 @@ const Ctor = typeof NativeCtor === 'function' ? NativeCtor : Error; | ||
error.stack = response[3]; | ||
for (const key in extra) { | ||
@@ -221,36 +188,24 @@ // @ts-expect-error: no index | ||
} | ||
this._onProcessEnd(error, null); | ||
break; | ||
case _types.PARENT_MESSAGE_SETUP_ERROR: | ||
error = new Error(`Error when calling setup: ${response[2]}`); // @ts-expect-error: adding custom properties to errors. | ||
error = new Error(`Error when calling setup: ${response[2]}`); | ||
// @ts-expect-error: adding custom properties to errors. | ||
error.type = response[1]; | ||
error.stack = response[3]; | ||
this._onProcessEnd(error, null); | ||
break; | ||
case _types.PARENT_MESSAGE_CUSTOM: | ||
this._onCustomMessage(response[1]); | ||
break; | ||
case _types.PARENT_MESSAGE_MEM_USAGE: | ||
this._childIdleMemoryUsage = response[1]; | ||
if (this._resolveMemoryUsage) { | ||
this._resolveMemoryUsage(response[1]); | ||
this._resolveMemoryUsage = undefined; | ||
this._memoryUsagePromise = undefined; | ||
} | ||
this._performRestartIfRequired(); | ||
break; | ||
default: | ||
@@ -260,7 +215,5 @@ throw new TypeError(`Unexpected response from worker: ${response[0]}`); | ||
} | ||
_onExit(exitCode) { | ||
this._workerReadyPromise = undefined; | ||
this._resolveWorkerReady = undefined; | ||
if (exitCode !== 0 && this.state === _types.WorkerStates.OUT_OF_MEMORY) { | ||
@@ -271,3 +224,2 @@ this._onProcessEnd( | ||
); | ||
this._shutdown(); | ||
@@ -281,3 +233,2 @@ } else if ( | ||
this.initialize(); | ||
if (this._request) { | ||
@@ -290,60 +241,49 @@ this._worker.postMessage(this._request); | ||
} | ||
waitForExit() { | ||
return this._exitPromise; | ||
} | ||
forceExit() { | ||
this.state = _types.WorkerStates.SHUTTING_DOWN; | ||
this._worker.terminate(); | ||
} | ||
send(request, onProcessStart, onProcessEnd, onCustomMessage) { | ||
onProcessStart(this); | ||
this._onProcessEnd = (...args) => { | ||
const hasRequest = !!this._request; | ||
this._onProcessEnd = (...args) => { | ||
const hasRequest = !!this._request; // Clean the request to avoid sending past requests to workers that fail | ||
// Clean the request to avoid sending past requests to workers that fail | ||
// while waiting for a new request (timers, unhandled rejections...) | ||
this._request = null; | ||
if (this._childIdleMemoryUsageLimit && hasRequest) { | ||
this.checkMemoryUsage(); | ||
} | ||
const res = onProcessEnd?.(...args); | ||
const res = onProcessEnd?.(...args); // Clean up the reference so related closures can be garbage collected. | ||
// Clean up the reference so related closures can be garbage collected. | ||
onProcessEnd = null; | ||
return res; | ||
}; | ||
this._onCustomMessage = (...arg) => onCustomMessage(...arg); | ||
this._request = request; | ||
this._retries = 0; | ||
this._worker.postMessage(request); | ||
} | ||
getWorkerId() { | ||
return this._options.workerId; | ||
} | ||
getStdout() { | ||
return this._stdout; | ||
} | ||
getStderr() { | ||
return this._stderr; | ||
} | ||
_performRestartIfRequired() { | ||
if (this._memoryUsageCheck) { | ||
this._memoryUsageCheck = false; | ||
let limit = this._childIdleMemoryUsageLimit; // TODO: At some point it would make sense to make use of | ||
let limit = this._childIdleMemoryUsageLimit; | ||
// TODO: At some point it would make sense to make use of | ||
// stringToBytes found in jest-config, however as this | ||
// package does not have any dependencies on an other jest | ||
// packages that can wait until some other time. | ||
if (limit && limit > 0 && limit <= 1) { | ||
@@ -354,3 +294,2 @@ limit = Math.floor((0, _os().totalmem)() * limit); | ||
} | ||
if ( | ||
@@ -362,3 +301,2 @@ limit && | ||
this.state = _types.WorkerStates.RESTARTING; | ||
this._worker.terminate(); | ||
@@ -368,2 +306,3 @@ } | ||
} | ||
/** | ||
@@ -374,3 +313,2 @@ * Gets the last reported memory usage. | ||
*/ | ||
getMemoryUsage() { | ||
@@ -384,3 +322,2 @@ if (!this._memoryUsagePromise) { | ||
this._memoryUsagePromise = promise; | ||
if (!this._worker.threadId) { | ||
@@ -392,3 +329,2 @@ rejectCallback(new Error('Child process is not running.')); | ||
} | ||
try { | ||
@@ -401,16 +337,13 @@ this._worker.postMessage([_types.CHILD_MESSAGE_MEM_USAGE]); | ||
} | ||
return promise; | ||
} | ||
return this._memoryUsagePromise; | ||
} | ||
/** | ||
* Gets updated memory usage and restarts if required | ||
*/ | ||
checkMemoryUsage() { | ||
if (this._childIdleMemoryUsageLimit) { | ||
this._memoryUsageCheck = true; | ||
this._worker.postMessage([_types.CHILD_MESSAGE_MEM_USAGE]); | ||
@@ -423,2 +356,3 @@ } else { | ||
} | ||
/** | ||
@@ -429,7 +363,5 @@ * Gets the thread id of the worker. | ||
*/ | ||
getWorkerSystemId() { | ||
return this._worker.threadId; | ||
} | ||
isWorkerRunning() { | ||
@@ -439,3 +371,2 @@ return this._worker.threadId >= 0; | ||
} | ||
exports.default = ExperimentalWorker; |
@@ -5,12 +5,8 @@ 'use strict'; | ||
const data = require('jest-util'); | ||
_jestUtil = function () { | ||
return data; | ||
}; | ||
return data; | ||
} | ||
var _types = require('../types'); | ||
/** | ||
@@ -22,5 +18,7 @@ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | ||
*/ | ||
let file = null; | ||
let setupArgs = []; | ||
let initialized = false; | ||
/** | ||
@@ -39,3 +37,2 @@ * This file is a small bootstrapper for workers. It sets up the communication | ||
*/ | ||
const messageListener = request => { | ||
@@ -46,5 +43,4 @@ switch (request[0]) { | ||
file = init[2]; | ||
setupArgs = request[3]; | ||
setupArgs = init[3]; | ||
break; | ||
case _types.CHILD_MESSAGE_CALL: | ||
@@ -54,11 +50,8 @@ const call = request; | ||
break; | ||
case _types.CHILD_MESSAGE_END: | ||
end(); | ||
break; | ||
case _types.CHILD_MESSAGE_MEM_USAGE: | ||
reportMemoryUsage(); | ||
break; | ||
default: | ||
@@ -70,5 +63,3 @@ throw new TypeError( | ||
}; | ||
process.on('message', messageListener); | ||
function reportSuccess(result) { | ||
@@ -78,14 +69,10 @@ if (!process || !process.send) { | ||
} | ||
process.send([_types.PARENT_MESSAGE_OK, result]); | ||
} | ||
function reportClientError(error) { | ||
return reportError(error, _types.PARENT_MESSAGE_CLIENT_ERROR); | ||
} | ||
function reportInitializeError(error) { | ||
return reportError(error, _types.PARENT_MESSAGE_SETUP_ERROR); | ||
} | ||
function reportMemoryUsage() { | ||
@@ -95,7 +82,5 @@ if (!process || !process.send) { | ||
} | ||
const msg = [_types.PARENT_MESSAGE_MEM_USAGE, process.memoryUsage().heapUsed]; | ||
process.send(msg); | ||
} | ||
function reportError(error, type) { | ||
@@ -105,7 +90,5 @@ if (!process || !process.send) { | ||
} | ||
if (error == null) { | ||
error = new Error('"null" or "undefined" thrown'); | ||
} | ||
process.send([ | ||
@@ -116,9 +99,11 @@ type, | ||
error.stack, | ||
typeof error === 'object' ? {...error} : error | ||
typeof error === 'object' | ||
? { | ||
...error | ||
} | ||
: error | ||
]); | ||
} | ||
function end() { | ||
const main = require(file); | ||
if (!main.teardown) { | ||
@@ -128,6 +113,4 @@ exitProcess(); | ||
} | ||
execFunction(main.teardown, main, [], exitProcess, exitProcess); | ||
} | ||
function exitProcess() { | ||
@@ -137,18 +120,13 @@ // Clean up open handles so the process ideally exits gracefully | ||
} | ||
function execMethod(method, args) { | ||
const main = require(file); | ||
let fn; | ||
if (method === 'default') { | ||
fn = main.__esModule ? main['default'] : main; | ||
fn = main.__esModule ? main.default : main; | ||
} else { | ||
fn = main[method]; | ||
} | ||
function execHelper() { | ||
execFunction(fn, main, args, reportSuccess, reportClientError); | ||
} | ||
if (initialized || !main.setup) { | ||
@@ -158,10 +136,7 @@ execHelper(); | ||
} | ||
initialized = true; | ||
execFunction(main.setup, main, setupArgs, execHelper, reportInitializeError); | ||
} | ||
function execFunction(fn, ctx, args, onResult, onError) { | ||
let result; | ||
try { | ||
@@ -173,3 +148,2 @@ result = fn.apply(ctx, args); | ||
} | ||
if ((0, _jestUtil().isPromise)(result)) { | ||
@@ -176,0 +150,0 @@ result.then(onResult, onError); |
@@ -5,22 +5,15 @@ 'use strict'; | ||
const data = require('worker_threads'); | ||
_worker_threads = function () { | ||
return data; | ||
}; | ||
return data; | ||
} | ||
function _jestUtil() { | ||
const data = require('jest-util'); | ||
_jestUtil = function () { | ||
return data; | ||
}; | ||
return data; | ||
} | ||
var _types = require('../types'); | ||
/** | ||
@@ -32,5 +25,7 @@ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | ||
*/ | ||
let file = null; | ||
let setupArgs = []; | ||
let initialized = false; | ||
/** | ||
@@ -49,3 +44,2 @@ * This file is a small bootstrapper for workers. It sets up the communication | ||
*/ | ||
const messageListener = request => { | ||
@@ -56,6 +50,5 @@ switch (request[0]) { | ||
file = init[2]; | ||
setupArgs = request[3]; | ||
process.env.JEST_WORKER_ID = request[4]; | ||
setupArgs = init[3]; | ||
process.env.JEST_WORKER_ID = init[4]; | ||
break; | ||
case _types.CHILD_MESSAGE_CALL: | ||
@@ -65,11 +58,8 @@ const call = request; | ||
break; | ||
case _types.CHILD_MESSAGE_END: | ||
end(); | ||
break; | ||
case _types.CHILD_MESSAGE_MEM_USAGE: | ||
reportMemoryUsage(); | ||
break; | ||
default: | ||
@@ -81,5 +71,3 @@ throw new TypeError( | ||
}; | ||
_worker_threads().parentPort.on('message', messageListener); | ||
function reportMemoryUsage() { | ||
@@ -89,8 +77,5 @@ if (_worker_threads().isMainThread) { | ||
} | ||
const msg = [_types.PARENT_MESSAGE_MEM_USAGE, process.memoryUsage().heapUsed]; | ||
_worker_threads().parentPort.postMessage(msg); | ||
} | ||
function reportSuccess(result) { | ||
@@ -100,14 +85,10 @@ if (_worker_threads().isMainThread) { | ||
} | ||
_worker_threads().parentPort.postMessage([_types.PARENT_MESSAGE_OK, result]); | ||
} | ||
function reportClientError(error) { | ||
return reportError(error, _types.PARENT_MESSAGE_CLIENT_ERROR); | ||
} | ||
function reportInitializeError(error) { | ||
return reportError(error, _types.PARENT_MESSAGE_SETUP_ERROR); | ||
} | ||
function reportError(error, type) { | ||
@@ -117,7 +98,5 @@ if (_worker_threads().isMainThread) { | ||
} | ||
if (error == null) { | ||
error = new Error('"null" or "undefined" thrown'); | ||
} | ||
_worker_threads().parentPort.postMessage([ | ||
@@ -128,9 +107,11 @@ type, | ||
error.stack, | ||
typeof error === 'object' ? {...error} : error | ||
typeof error === 'object' | ||
? { | ||
...error | ||
} | ||
: error | ||
]); | ||
} | ||
function end() { | ||
const main = require(file); | ||
if (!main.teardown) { | ||
@@ -140,6 +121,4 @@ exitProcess(); | ||
} | ||
execFunction(main.teardown, main, [], exitProcess, exitProcess); | ||
} | ||
function exitProcess() { | ||
@@ -149,18 +128,13 @@ // Clean up open handles so the worker ideally exits gracefully | ||
} | ||
function execMethod(method, args) { | ||
const main = require(file); | ||
let fn; | ||
if (method === 'default') { | ||
fn = main.__esModule ? main['default'] : main; | ||
fn = main.__esModule ? main.default : main; | ||
} else { | ||
fn = main[method]; | ||
} | ||
function execHelper() { | ||
execFunction(fn, main, args, reportSuccess, reportClientError); | ||
} | ||
if (initialized || !main.setup) { | ||
@@ -170,10 +144,7 @@ execHelper(); | ||
} | ||
initialized = true; | ||
execFunction(main.setup, main, setupArgs, execHelper, reportInitializeError); | ||
} | ||
function execFunction(fn, ctx, args, onResult, onError) { | ||
let result; | ||
try { | ||
@@ -185,3 +156,2 @@ result = fn.apply(ctx, args); | ||
} | ||
if ((0, _jestUtil().isPromise)(result)) { | ||
@@ -188,0 +158,0 @@ result.then(onResult, onError); |
@@ -7,15 +7,10 @@ 'use strict'; | ||
exports.default = void 0; | ||
function _stream() { | ||
const data = require('stream'); | ||
_stream = function () { | ||
return data; | ||
}; | ||
return data; | ||
} | ||
var _types = require('../types'); | ||
/** | ||
@@ -27,2 +22,3 @@ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. | ||
*/ | ||
class WorkerAbstract extends _stream().EventEmitter { | ||
@@ -39,7 +35,5 @@ /** | ||
_resolveWorkerReady; | ||
get state() { | ||
return this.#state; | ||
} | ||
set state(value) { | ||
@@ -52,6 +46,4 @@ if (this.#state !== value) { | ||
} | ||
constructor(options) { | ||
super(); | ||
if (typeof options.on === 'object') { | ||
@@ -70,7 +62,5 @@ for (const [event, handlers] of Object.entries(options.on)) { | ||
} | ||
this._exitPromise = new Promise(resolve => { | ||
this._resolveExitPromise = resolve; | ||
}); | ||
this._exitPromise.then(() => { | ||
@@ -80,2 +70,3 @@ this.state = _types.WorkerStates.SHUT_DOWN; | ||
} | ||
/** | ||
@@ -86,3 +77,2 @@ * Wait for the worker child process to be ready to handle requests. | ||
*/ | ||
waitForWorkerReady() { | ||
@@ -93,3 +83,2 @@ if (!this._workerReadyPromise) { | ||
let to; | ||
switch (this.state) { | ||
@@ -106,3 +95,2 @@ case _types.WorkerStates.OUT_OF_MEMORY: | ||
break; | ||
case _types.WorkerStates.STARTING: | ||
@@ -113,3 +101,2 @@ case _types.WorkerStates.RESTARTING: | ||
resolve(); | ||
if (to) { | ||
@@ -119,5 +106,3 @@ clearTimeout(to); | ||
}; | ||
break; | ||
case _types.WorkerStates.OK: | ||
@@ -128,3 +113,2 @@ settled = true; | ||
} | ||
if (!settled) { | ||
@@ -139,5 +123,5 @@ to = setTimeout(() => { | ||
} | ||
return this._workerReadyPromise; | ||
} | ||
/** | ||
@@ -147,15 +131,12 @@ * Used to shut down the current working instance once the children have been | ||
*/ | ||
_shutdown() { | ||
this.state === _types.WorkerStates.SHUT_DOWN; // End the permanent stream so the merged stream end too | ||
this.state === _types.WorkerStates.SHUT_DOWN; | ||
// End the permanent stream so the merged stream end too | ||
if (this._fakeStream) { | ||
this._fakeStream.end(); | ||
this._fakeStream = null; | ||
} | ||
this._resolveExitPromise(); | ||
} | ||
_getFakeStream() { | ||
@@ -165,7 +146,5 @@ if (!this._fakeStream) { | ||
} | ||
return this._fakeStream; | ||
} | ||
} | ||
exports.default = WorkerAbstract; |
{ | ||
"name": "jest-worker", | ||
"version": "29.1.2", | ||
"version": "29.2.0", | ||
"repository": { | ||
@@ -21,3 +21,3 @@ "type": "git", | ||
"@types/node": "*", | ||
"jest-util": "^29.1.2", | ||
"jest-util": "^29.2.0", | ||
"merge-stream": "^2.0.0", | ||
@@ -31,3 +31,3 @@ "supports-color": "^8.0.0" | ||
"get-stream": "^6.0.0", | ||
"jest-leak-detector": "^29.1.2", | ||
"jest-leak-detector": "^29.2.0", | ||
"tsd-lite": "^0.6.0", | ||
@@ -42,3 +42,3 @@ "worker-farm": "^1.6.0" | ||
}, | ||
"gitHead": "3c31dd619e8c022cde53f40fa12ea2a67f4752ce" | ||
"gitHead": "ee5b37a4f4433afcfffb0356cea47739d8092287" | ||
} |
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
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
2249
84461
Updatedjest-util@^29.2.0