Socket
Socket
Sign inDemoInstall

jest-worker

Package Overview
Dependencies
Maintainers
5
Versions
171
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jest-worker - npm Package Compare versions

Comparing version 29.1.2 to 29.2.0

33

build/base/BaseWorkerPool.js

@@ -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"
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc