poolifier
Version:
Fast and small Node.js Worker_Threads and Cluster Worker Pool
1,472 lines (1,463 loc) • 82.8 kB
TypeScript
import { TransferListItem, MessagePort, MessageChannel, WorkerOptions as WorkerOptions$1, Worker as Worker$1 } from 'node:worker_threads';
import { EventEmitter, EventEmitterAsyncResource } from 'node:events';
import { AsyncResource } from 'node:async_hooks';
import { EventLoopUtilization } from 'node:perf_hooks';
import { ClusterSettings, Worker } from 'node:cluster';
/**
* Circular buffer designed for positive numbers.
* @internal
*/
declare class CircularBuffer {
private readonly items;
private readonly maxArrayIdx;
private readIdx;
private writeIdx;
size: number;
/**
* @param size - Buffer size. @defaultValue defaultBufferSize
* @returns CircularBuffer.
*/
constructor(size?: number);
/**
* Checks the buffer size.
* @param size - Buffer size.
*/
private checkSize;
/**
* Checks whether the buffer is empty.
* @returns Whether the buffer is empty.
*/
empty(): boolean;
/**
* Checks whether the buffer is full.
* @returns Whether the buffer is full.
*/
full(): boolean;
/**
* Gets number from buffer.
* @returns Number from buffer.
*/
get(): number | undefined;
/**
* Puts number into buffer.
* @param number - Number to put into buffer.
*/
put(number: number): void;
/**
* Returns buffer as numbers' array.
* @returns Numbers' array.
*/
toArray(): number[];
}
/**
* Enumeration of worker choice strategies.
*/
declare const WorkerChoiceStrategies: Readonly<{
FAIR_SHARE: 'FAIR_SHARE';
INTERLEAVED_WEIGHTED_ROUND_ROBIN: 'INTERLEAVED_WEIGHTED_ROUND_ROBIN';
LEAST_BUSY: 'LEAST_BUSY';
LEAST_ELU: 'LEAST_ELU';
LEAST_USED: 'LEAST_USED';
ROUND_ROBIN: 'ROUND_ROBIN';
WEIGHTED_ROUND_ROBIN: 'WEIGHTED_ROUND_ROBIN';
}>;
/**
* Worker choice strategy.
*/
type WorkerChoiceStrategy = keyof typeof WorkerChoiceStrategies;
/**
* Enumeration of measurements.
*/
declare const Measurements: Readonly<{
elu: 'elu';
runTime: 'runTime';
waitTime: 'waitTime';
}>;
/**
* Measurement.
*/
type Measurement = keyof typeof Measurements;
/**
* Measurement options.
*/
interface MeasurementOptions {
/**
* Set measurement median.
*/
readonly median: boolean;
}
/**
* Worker choice strategy options.
*/
interface WorkerChoiceStrategyOptions {
/**
* Event loop utilization options.
* @defaultValue \{ median: false \}
*/
readonly elu?: MeasurementOptions;
/**
* Measurement to use in worker choice strategy supporting it.
*/
readonly measurement?: Measurement;
/**
* Runtime options.
* @defaultValue \{ median: false \}
*/
readonly runTime?: MeasurementOptions;
/**
* Wait time options.
* @defaultValue \{ median: false \}
*/
readonly waitTime?: MeasurementOptions;
/**
* Worker weights to use for weighted round robin worker selection strategies.
* A weight is tasks maximum execution time in milliseconds for a worker node.
* @defaultValue Weights computed automatically given the CPU performance.
*/
weights?: Record<number, number>;
}
/**
* Measurement statistics requirements.
* @internal
*/
interface MeasurementStatisticsRequirements {
/**
* Requires measurement aggregate.
*/
aggregate: boolean;
/**
* Requires measurement average.
*/
average: boolean;
/**
* Requires measurement median.
*/
median: boolean;
}
/**
* Pool worker node worker usage statistics requirements.
* @internal
*/
interface TaskStatisticsRequirements {
/**
* Tasks event loop utilization requirements.
*/
readonly elu: MeasurementStatisticsRequirements;
/**
* Tasks runtime requirements.
*/
readonly runTime: MeasurementStatisticsRequirements;
/**
* Tasks wait time requirements.
*/
readonly waitTime: MeasurementStatisticsRequirements;
}
/**
* Strategy policy.
* @internal
*/
interface StrategyPolicy {
/**
* Expects the newly created dynamic worker to be flagged as ready.
*/
readonly dynamicWorkerReady: boolean;
/**
* Expects tasks execution on the newly created dynamic worker.
*/
readonly dynamicWorkerUsage: boolean;
}
/**
* Worker choice strategy interface.
* @internal
*/
interface IWorkerChoiceStrategy {
/**
* Chooses a worker node in the pool and returns its key.
* If no worker nodes are not eligible, `undefined` is returned.
* If `undefined` is returned, the caller retry.
* @returns The worker node key or `undefined`.
*/
readonly choose: () => number | undefined;
/**
* Removes the worker node key from strategy internals.
* @param workerNodeKey - The worker node key.
* @returns `true` if the worker node key is removed, `false` otherwise.
*/
readonly remove: (workerNodeKey: number) => boolean;
/**
* Resets strategy internals.
* @returns `true` if the reset is successful, `false` otherwise.
*/
readonly reset: () => boolean;
/**
* Sets the worker choice strategy options.
* @param opts - The worker choice strategy options.
*/
readonly setOptions: (opts: undefined | WorkerChoiceStrategyOptions) => void;
/**
* Strategy policy.
*/
readonly strategyPolicy: StrategyPolicy;
/**
* Tasks statistics requirements.
*/
readonly taskStatisticsRequirements: TaskStatisticsRequirements;
/**
* Updates the worker node key strategy internals.
* This is called after a task has been executed on a worker node.
* @returns `true` if the update is successful, `false` otherwise.
*/
readonly update: (workerNodeKey: number) => boolean;
}
/**
* Enumeration of kill behaviors.
*/
declare const KillBehaviors: Readonly<{
HARD: 'HARD';
SOFT: 'SOFT';
}>;
/**
* Kill behavior.
*/
type KillBehavior = keyof typeof KillBehaviors;
/**
* Handler called when a worker is killed.
*/
type KillHandler = () => Promise<void> | void;
/**
* Options for workers.
*/
interface WorkerOptions {
/**
* `killBehavior` dictates if your worker will be deleted in case a task is active on it.
*
* - SOFT: If `currentTime - lastActiveTime` is greater than `maxInactiveTime` but the worker is stealing tasks or a task is executing or queued, then the worker **won't** be deleted.
* - HARD: If `currentTime - lastActiveTime` is greater than `maxInactiveTime` but the worker is stealing tasks or a task is executing or queued, then the worker will be deleted.
*
* This option only apply to the newly created workers.
* @defaultValue KillBehaviors.SOFT
*/
killBehavior?: KillBehavior;
/**
* The function to call when a worker is killed.
* @defaultValue `() => {}`
*/
killHandler?: KillHandler;
/**
* Maximum waiting time in milliseconds for tasks on newly created workers. It must be greater or equal than 5.
*
* After this time, newly created workers will be terminated.
* The last active time of your worker will be updated when it terminates a task.
*
* - If `killBehavior` is set to `KillBehaviors.HARD` this value represents also the timeout for the tasks that you submit to the pool,
* when this timeout expires your tasks is interrupted before completion and removed. The worker is killed if is not part of the minimum size of the pool.
* - If `killBehavior` is set to `KillBehaviors.SOFT` your tasks have no timeout and your workers will not be terminated until your task is completed.
* @defaultValue 60000
*/
maxInactiveTime?: number;
}
/**
* Worker error.
* @typeParam Data - Type of data sent to the worker triggering an error. This can only be structured-cloneable data.
*/
interface WorkerError<Data = unknown> {
/**
* Data triggering the error.
*/
readonly data?: Data;
/**
* Error object.
*/
readonly error?: Error;
/**
* Error message.
*/
readonly message: string;
/**
* Task function name triggering the error.
*/
readonly name?: string;
/**
* Error stack trace.
*/
readonly stack?: string;
}
/**
* Task performance.
* @internal
*/
interface TaskPerformance {
/**
* Task event loop utilization.
*/
readonly elu?: EventLoopUtilization;
/**
* Task name.
*/
readonly name: string;
/**
* Task runtime.
*/
readonly runTime?: number;
/**
* Task performance timestamp.
*/
readonly timestamp: number;
}
/**
* Worker task performance statistics computation settings.
* @internal
*/
interface WorkerStatistics {
/**
* Whether the worker computes the task event loop utilization (ELU) or not.
*/
readonly elu: boolean;
/**
* Whether the worker computes the task runtime or not.
*/
readonly runTime: boolean;
}
/**
* Task function properties.
*/
interface TaskFunctionProperties {
/**
* Task function name.
*/
readonly name: string;
/**
* Task function priority. Lower values have higher priority.
*/
readonly priority?: number;
/**
* Task function worker choice strategy.
*/
readonly strategy?: WorkerChoiceStrategy;
}
/**
* Message object that is passed as a task between main worker and worker.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @internal
*/
interface Task<Data = unknown> {
/**
* Task input data that will be passed to the worker.
*/
readonly data?: Data;
/**
* Task name.
*/
readonly name?: string;
/**
* Task priority. Lower values have higher priority.
* @defaultValue 0
*/
readonly priority?: number;
/**
* Task worker choice strategy.
*/
readonly strategy?: WorkerChoiceStrategy;
/**
* Task UUID.
*/
readonly taskId?: `${string}-${string}-${string}-${string}-${string}`;
/**
* Timestamp.
*/
readonly timestamp?: number;
/**
* Array of transferable objects.
*/
readonly transferList?: readonly TransferListItem[];
}
/**
* Message object that is passed between main worker and worker.
* @typeParam Data - Type of data sent to the worker or execution response. This can only be structured-cloneable data.
* @typeParam ErrorData - Type of data sent to the worker triggering an error. This can only be structured-cloneable data.
* @internal
*/
interface MessageValue<Data = unknown, ErrorData = unknown> extends Task<Data> {
/**
* Whether the worker starts or stops its activity check.
*/
readonly checkActive?: boolean;
/**
* Kill code.
*/
readonly kill?: 'failure' | 'success' | KillBehavior | true;
/**
* Message port.
*/
readonly port?: MessagePort;
/**
* Whether the worker is ready or not.
*/
readonly ready?: boolean;
/**
* Whether the worker computes the given statistics or not.
*/
readonly statistics?: WorkerStatistics;
/**
* Task function serialized to string.
*/
readonly taskFunction?: string;
/**
* Task function operation:
* - `'add'` - Add a task function.
* - `'remove'` - Remove a task function.
* - `'default'` - Set a task function as default.
*/
readonly taskFunctionOperation?: 'add' | 'default' | 'remove';
/**
* Whether the task function operation is successful or not.
*/
readonly taskFunctionOperationStatus?: boolean;
/**
* Task function properties.
*/
readonly taskFunctionProperties?: TaskFunctionProperties;
/**
* Task functions properties.
*/
readonly taskFunctionsProperties?: TaskFunctionProperties[];
/**
* Task performance.
*/
readonly taskPerformance?: TaskPerformance;
/**
* Worker error.
*/
readonly workerError?: WorkerError<ErrorData>;
/**
* Worker id.
*/
readonly workerId?: number;
}
/**
* An object holding the task execution response promise resolve/reject callbacks.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
* @internal
*/
interface PromiseResponseWrapper<Response = unknown> {
/**
* The asynchronous resource used to track the task execution.
*/
readonly asyncResource?: AsyncResource;
/**
* Reject callback to reject the promise.
*/
readonly reject: (reason?: unknown) => void;
/**
* Resolve callback to fulfill the promise.
*/
readonly resolve: (value: PromiseLike<Response> | Response) => void;
/**
* The worker node key executing the task.
*/
readonly workerNodeKey: number;
}
/**
* Remove readonly modifier from all properties of T.
* @typeParam T - Type to remove readonly modifier.
* @internal
*/
type Writable<T> = {
-readonly [P in keyof T]: T[P];
};
/**
* Task synchronous function that can be executed.
* @param data - Data sent to the worker.
* @returns Execution response.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
*/
type TaskSyncFunction<Data = unknown, Response = unknown> = (data?: Data) => Response;
/**
* Task asynchronous function that can be executed.
* This function must return a promise.
* @param data - Data sent to the worker.
* @returns Execution response promise.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
*/
type TaskAsyncFunction<Data = unknown, Response = unknown> = (data?: Data) => Promise<Response>;
/**
* Task function that can be executed.
* This function can be synchronous or asynchronous.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
*/
type TaskFunction<Data = unknown, Response = unknown> = TaskAsyncFunction<Data, Response> | TaskSyncFunction<Data, Response>;
/**
* Task function object.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
*/
interface TaskFunctionObject<Data = unknown, Response = unknown> {
/**
* Task function priority. Lower values have higher priority.
*/
priority?: number;
/**
* Task function worker choice strategy.
*/
strategy?: WorkerChoiceStrategy;
/**
* Task function.
*/
taskFunction: TaskFunction<Data, Response>;
}
/**
* Tasks functions that can be executed.
* The key is the name of the task function or task function object.
* The value is the task function or task function object.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
*/
type TaskFunctions<Data = unknown, Response = unknown> = Record<string, TaskFunction<Data, Response> | TaskFunctionObject<Data, Response>>;
/**
* Task function operation result.
*/
interface TaskFunctionOperationResult {
error?: Error;
status: boolean;
}
/**
* Callback invoked when the worker has started successfully.
* @typeParam Worker - Type of worker.
*/
type OnlineHandler<Worker extends IWorker> = (this: Worker) => void;
/**
* Callback invoked if the worker has received a message.
* @typeParam Worker - Type of worker.
*/
type MessageHandler<Worker extends IWorker> = (this: Worker, message: unknown) => void;
/**
* Callback invoked if the worker raised an error.
* @typeParam Worker - Type of worker.
*/
type ErrorHandler<Worker extends IWorker> = (this: Worker, error: Error) => void;
/**
* Callback invoked when the worker exits successfully.
* @typeParam Worker - Type of worker.
*/
type ExitHandler<Worker extends IWorker> = (this: Worker, exitCode: number) => void;
/**
* Worker event handler.
* @typeParam Worker - Type of worker.
*/
type EventHandler<Worker extends IWorker> = ErrorHandler<Worker> | ExitHandler<Worker> | MessageHandler<Worker> | OnlineHandler<Worker>;
/**
* Measurement statistics.
* @internal
*/
interface MeasurementStatistics {
/**
* Measurement aggregate.
*/
aggregate?: number;
/**
* Measurement average.
*/
average?: number;
/**
* Measurement history.
*/
readonly history: CircularBuffer;
/**
* Measurement maximum.
*/
maximum?: number;
/**
* Measurement median.
*/
median?: number;
/**
* Measurement minimum.
*/
minimum?: number;
}
/**
* Event loop utilization measurement statistics.
* @internal
*/
interface EventLoopUtilizationMeasurementStatistics {
readonly active: MeasurementStatistics;
readonly idle: MeasurementStatistics;
utilization?: number;
}
/**
* Task statistics.
* @internal
*/
interface TaskStatistics {
/**
* Number of executed tasks.
*/
executed: number;
/**
* Number of executing tasks.
*/
executing: number;
/**
* Number of failed tasks.
*/
failed: number;
/**
* Maximum number of queued tasks.
*/
readonly maxQueued?: number;
/**
* Number of queued tasks.
*/
readonly queued: number;
/**
* Number of sequentially stolen tasks.
*/
sequentiallyStolen: number;
/**
* Number of stolen tasks.
*/
stolen: number;
}
/**
* Enumeration of worker types.
*/
declare const WorkerTypes: Readonly<{
cluster: 'cluster';
thread: 'thread';
}>;
/**
* Worker type.
*/
type WorkerType = keyof typeof WorkerTypes;
/**
* Worker information.
* @internal
*/
interface WorkerInfo {
/**
* Back pressure flag.
* This flag is set to `true` when worker node tasks queue is back pressured.
*/
backPressure: boolean;
/**
* Back pressure stealing flag.
* This flag is set to `true` when worker node is stealing one task from another back pressured worker node.
*/
backPressureStealing: boolean;
/**
* Continuous stealing flag.
* This flag is set to `true` when worker node is continuously stealing tasks from other worker nodes.
*/
continuousStealing: boolean;
/**
* Dynamic flag.
*/
dynamic: boolean;
/**
* Worker id.
*/
readonly id: number | undefined;
/**
* Ready flag.
*/
ready: boolean;
/**
* Stealing flag.
* This flag is set to `true` when worker node is stealing one task from another worker node.
*/
stealing: boolean;
/**
* Stolen flag.
* This flag is set to `true` when worker node has one task stolen from another worker node.
*/
stolen: boolean;
/**
* Task functions properties.
*/
taskFunctionsProperties?: TaskFunctionProperties[];
/**
* Worker type.
*/
readonly type: WorkerType;
}
/**
* Worker usage statistics.
* @internal
*/
interface WorkerUsage {
/**
* Tasks event loop utilization statistics.
*/
readonly elu: EventLoopUtilizationMeasurementStatistics;
/**
* Tasks runtime statistics.
*/
readonly runTime: MeasurementStatistics;
/**
* Tasks statistics.
*/
readonly tasks: TaskStatistics;
/**
* Tasks wait time statistics.
*/
readonly waitTime: MeasurementStatistics;
}
/**
* Worker choice strategy data.
* @internal
*/
interface StrategyData {
virtualTaskEndTimestamp?: number;
}
/**
* Worker interface.
*/
interface IWorker extends EventEmitter {
/**
* Cluster worker disconnect.
*/
readonly disconnect?: () => void;
/**
* Cluster worker id.
*/
readonly id?: number;
/**
* Cluster worker kill.
*/
readonly kill?: (signal?: string) => void;
/**
* Registers an event handler.
* @param event - The event.
* @param handler - The event handler.
*/
readonly on: (event: string, handler: EventHandler<this>) => this;
/**
* Registers once an event handler.
* @param event - The event.
* @param handler - The event handler.
*/
readonly once: (event: string, handler: EventHandler<this>) => this;
/**
* Stop all JavaScript execution in the worker thread as soon as possible.
* Returns a Promise for the exit code that is fulfilled when the `'exit' event` is emitted.
*/
readonly terminate?: () => Promise<number>;
/**
* Worker thread worker id.
*/
readonly threadId?: number;
/**
* Calling `unref()` on a worker allows the thread to exit if this is the only
* active handle in the event system. If the worker is already `unref()`ed calling`unref()` again has no effect.
* @since v10.5.0
*/
readonly unref?: () => void;
}
/**
* Worker node options.
* @internal
*/
interface WorkerNodeOptions {
env?: Record<string, unknown>;
tasksQueueBackPressureSize: number | undefined;
tasksQueueBucketSize: number | undefined;
tasksQueuePriority: boolean | undefined;
workerOptions?: WorkerOptions$1;
}
/**
* Worker node interface.
* @typeParam Worker - Type of worker.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @internal
*/
interface IWorkerNode<Worker extends IWorker, Data = unknown> extends EventEmitter {
/**
* Clears tasks queue.
*/
readonly clearTasksQueue: () => void;
/**
* Deletes task function worker usage statistics.
* @param name - The task function name.
* @returns `true` if the task function worker usage statistics were deleted, `false` otherwise.
*/
readonly deleteTaskFunctionWorkerUsage: (name: string) => boolean;
/**
* Dequeue last prioritized task.
* @returns The dequeued task.
*/
readonly dequeueLastPrioritizedTask: () => Task<Data> | undefined;
/**
* Dequeue task.
* @param bucket - The prioritized bucket to dequeue from. @defaultValue 0
* @returns The dequeued task.
*/
readonly dequeueTask: (bucket?: number) => Task<Data> | undefined;
/**
* Enqueue task.
* @param task - The task to queue.
* @returns The tasks queue size.
*/
readonly enqueueTask: (task: Task<Data>) => number;
/**
* Gets task function worker usage statistics.
* @param name - The task function name.
* @returns The task function worker usage statistics if the task function worker usage statistics are initialized, `undefined` otherwise.
*/
readonly getTaskFunctionWorkerUsage: (name: string) => undefined | WorkerUsage;
/**
* Worker info.
*/
readonly info: WorkerInfo;
/**
* Message channel (worker thread only).
*/
readonly messageChannel?: MessageChannel;
/**
* Registers once a worker event handler.
* @param event - The event.
* @param handler - The event handler.
*/
readonly registerOnceWorkerEventHandler: (event: string, handler: EventHandler<Worker>) => void;
/**
* Registers a worker event handler.
* @param event - The event.
* @param handler - The event handler.
*/
readonly registerWorkerEventHandler: (event: string, handler: EventHandler<Worker>) => void;
/**
* Sets tasks queue priority.
* @param enablePriority - Whether to enable tasks queue priority.
*/
readonly setTasksQueuePriority: (enablePriority: boolean) => void;
/**
* Worker choice strategy data.
* This is used to store data that are specific to the worker choice strategy.
*/
strategyData?: StrategyData;
/**
* Tasks queue back pressure size.
* This is the number of tasks that can be enqueued before the worker node has back pressure.
*/
tasksQueueBackPressureSize: number;
/**
* Tasks queue size.
* @returns The tasks queue size.
*/
readonly tasksQueueSize: () => number;
/**
* Terminates the worker node.
*/
readonly terminate: () => Promise<void>;
/**
* Worker usage statistics.
*/
readonly usage: WorkerUsage;
/**
* Worker.
*/
readonly worker: Worker;
}
/**
* Worker node event detail.
* @internal
*/
interface WorkerNodeEventDetail {
workerId?: number;
workerNodeKey?: number;
}
/**
* Enumeration of pool types.
*/
declare const PoolTypes: Readonly<{
dynamic: 'dynamic';
fixed: 'fixed';
}>;
/**
* Pool type.
*/
type PoolType = keyof typeof PoolTypes;
/**
* Enumeration of pool events.
*/
declare const PoolEvents: Readonly<{
backPressure: 'backPressure';
backPressureEnd: 'backPressureEnd';
busy: 'busy';
busyEnd: 'busyEnd';
destroy: 'destroy';
empty: 'empty';
error: 'error';
full: 'full';
fullEnd: 'fullEnd';
ready: 'ready';
taskError: 'taskError';
}>;
/**
* Pool event.
*/
type PoolEvent = keyof typeof PoolEvents;
/**
* Pool information.
*/
interface PoolInfo {
readonly backPressure?: boolean;
/** Pool tasks back pressure worker nodes. */
readonly backPressureWorkerNodes?: number;
/** Pool busy worker nodes. */
readonly busyWorkerNodes: number;
readonly defaultStrategy: WorkerChoiceStrategy;
/** Pool dynamic worker nodes. */
readonly dynamicWorkerNodes?: number;
readonly elu?: {
active: {
readonly average?: number;
readonly maximum: number;
readonly median?: number;
readonly minimum: number;
};
idle: {
readonly average?: number;
readonly maximum: number;
readonly median?: number;
readonly minimum: number;
};
utilization: {
readonly average?: number;
readonly median?: number;
};
};
readonly executedTasks: number;
readonly executingTasks: number;
readonly failedTasks: number;
/** Pool idle worker nodes. */
readonly idleWorkerNodes: number;
readonly maxQueuedTasks?: number;
readonly maxSize: number;
readonly minSize: number;
readonly queuedTasks?: number;
readonly ready: boolean;
readonly runTime?: {
readonly average?: number;
readonly maximum: number;
readonly median?: number;
readonly minimum: number;
};
readonly started: boolean;
/** Pool tasks stealing worker nodes. */
readonly stealingWorkerNodes?: number;
readonly stolenTasks?: number;
readonly strategyRetries: number;
readonly type: PoolType;
/** Pool utilization. */
readonly utilization?: number;
readonly version: string;
readonly waitTime?: {
readonly average?: number;
readonly maximum: number;
readonly median?: number;
readonly minimum: number;
};
readonly worker: WorkerType;
/** Pool total worker nodes. */
readonly workerNodes: number;
}
/**
* Worker node tasks queue options.
*/
interface TasksQueueOptions {
/**
* Maximum number of tasks that can be executed concurrently on a worker node.
* @defaultValue 1
*/
readonly concurrency?: number;
/**
* Maximum tasks queue size per worker node flagging it as back pressured.
* @defaultValue (pool maximum size)^2
*/
readonly size?: number;
/**
* Queued tasks finished timeout in milliseconds at worker node termination.
* @defaultValue 2000
*/
readonly tasksFinishedTimeout?: number;
/**
* Whether to enable tasks stealing under back pressure.
* @defaultValue true
*/
readonly tasksStealingOnBackPressure?: boolean;
/**
* Ratio of worker nodes that can steal tasks from another worker node.
* @defaultValue 0.6
*/
readonly tasksStealingRatio?: number;
/**
* Whether to enable task stealing on idle.
* @defaultValue true
*/
readonly taskStealing?: boolean;
}
/**
* Options for a poolifier pool.
* @typeParam Worker - Type of worker.
*/
interface PoolOptions<Worker extends IWorker> {
/**
* Pool events integrated with async resource emission.
* @defaultValue true
*/
enableEvents?: boolean;
/**
* Pool worker node tasks queue.
* @defaultValue false
*/
enableTasksQueue?: boolean;
/**
* Key/value pairs to add to worker process environment.
* @see https://nodejs.org/api/cluster.html#cluster_cluster_fork_env
*/
env?: Record<string, unknown>;
/**
* A function that will listen for error event on each worker.
* @defaultValue `() => {}`
*/
errorHandler?: ErrorHandler<Worker>;
/**
* A function that will listen for exit event on each worker.
* @defaultValue `() => {}`
*/
exitHandler?: ExitHandler<Worker>;
/**
* A function that will listen for message event on each worker.
* @defaultValue `() => {}`
*/
messageHandler?: MessageHandler<Worker>;
/**
* A function that will listen for online event on each worker.
* @defaultValue `() => {}`
*/
onlineHandler?: OnlineHandler<Worker>;
/**
* Restart worker on error.
*/
restartWorkerOnError?: boolean;
/**
* Cluster settings.
* @see https://nodejs.org/api/cluster.html#cluster_cluster_settings
*/
settings?: ClusterSettings;
/**
* Whether to start the minimum number of workers at pool initialization.
* @defaultValue true
*/
startWorkers?: boolean;
/**
* Pool worker node tasks queue options.
*/
tasksQueueOptions?: TasksQueueOptions;
/**
* The default worker choice strategy to use in this pool.
* @defaultValue WorkerChoiceStrategies.ROUND_ROBIN
*/
workerChoiceStrategy?: WorkerChoiceStrategy;
/**
* The worker choice strategy options.
*/
workerChoiceStrategyOptions?: WorkerChoiceStrategyOptions;
/**
* Worker options.
* @see https://nodejs.org/api/worker_threads.html#new-workerfilename-options
*/
workerOptions?: WorkerOptions$1;
}
/**
* Contract definition for a poolifier pool.
* @typeParam Worker - Type of worker which manages this pool.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
*/
interface IPool<Worker extends IWorker, Data = unknown, Response = unknown> {
/**
* Adds a task function to this pool.
* If a task function with the same name already exists, it will be overwritten.
* @param name - The name of the task function.
* @param fn - The task function.
* @returns `true` if the task function was added, `false` otherwise.
* @throws {@link https://nodejs.org/api/errors.html#class-typeerror} If the `name` parameter is not a string or an empty string.
* @throws {@link https://nodejs.org/api/errors.html#class-typeerror} If the `fn` parameter is not a function or task function object.
*/
readonly addTaskFunction: (name: string, fn: TaskFunction<Data, Response> | TaskFunctionObject<Data, Response>) => Promise<boolean>;
/**
* Terminates all workers in this pool.
*/
readonly destroy: () => Promise<void>;
/**
* Pool event emitter integrated with async resource.
* The async tracking tooling identifier is `poolifier:<PoolType>-<WorkerType>-pool`.
*
* Events that can currently be listened to:
*
* - `'ready'`: Emitted when the number of workers created in the pool has reached the minimum size expected and are ready. If the pool is dynamic with a minimum number of workers set to zero, this event is emitted when the pool is started.
* - `'busy'`: Emitted when the number of workers created in the pool has reached the maximum size expected and are executing concurrently their tasks quota.
* - `'busyEnd'`: Emitted when the number of workers created in the pool has reached the maximum size expected and are no longer executing concurrently their tasks quota.
* - `'full'`: Emitted when the pool is dynamic and the number of workers created has reached the maximum size expected.
* - `'fullEnd'`: Emitted when the pool is dynamic and the number of workers created has no longer reached the maximum size expected.
* - `'empty'`: Emitted when the pool is dynamic with a minimum number of workers set to zero and the number of workers has reached the minimum size expected.
* - `'destroy'`: Emitted when the pool is destroyed.
* - `'error'`: Emitted when an uncaught error occurs.
* - `'taskError'`: Emitted when an error occurs while executing a task.
* - `'backPressure'`: Emitted when the number of workers created in the pool has reached the maximum size expected and are back pressured (i.e. their tasks queue is full: queue size \>= maximum queue size).
* - `'backPressureEnd'`: Emitted when the number of workers created in the pool has reached the maximum size expected and are no longer back pressured (i.e. their tasks queue is no longer full: queue size \< maximum queue size).
*/
readonly emitter?: EventEmitterAsyncResource;
/**
* Enables/disables the worker node tasks queue in this pool.
* @param enable - Whether to enable or disable the worker node tasks queue.
* @param tasksQueueOptions - The worker node tasks queue options.
*/
readonly enableTasksQueue: (enable: boolean, tasksQueueOptions?: TasksQueueOptions) => void;
/**
* Executes the specified function in the worker constructor with the task data input parameter.
* @param data - The optional task input data for the specified task function. This can only be structured-cloneable data.
* @param name - The optional name of the task function to execute. If not specified, the default task function will be executed.
* @param transferList - An optional array of transferable objects to transfer ownership of. Ownership of the transferred objects is given to the chosen pool's worker_threads worker and they should not be used in the main thread afterwards.
* @returns Promise with a task function response that will be fulfilled when the task is completed.
*/
readonly execute: (data?: Data, name?: string, transferList?: readonly TransferListItem[]) => Promise<Response>;
/**
* Whether the specified task function exists in this pool.
* @param name - The name of the task function.
* @returns `true` if the task function exists, `false` otherwise.
*/
readonly hasTaskFunction: (name: string) => boolean;
/**
* Pool information.
*/
readonly info: PoolInfo;
/**
* Lists the properties of task functions available in this pool.
* @returns The properties of task functions available in this pool.
*/
readonly listTaskFunctionsProperties: () => TaskFunctionProperties[];
/**
* Executes the specified function in the worker constructor with the tasks data iterable input parameter.
* @param data - The tasks iterable input data for the specified task function. This can only be an iterable of structured-cloneable data.
* @param name - The optional name of the task function to execute. If not specified, the default task function will be executed.
* @param transferList - An optional array of transferable objects to transfer ownership of. Ownership of the transferred objects is given to the chosen pool's worker_threads worker and they should not be used in the main thread afterwards.
* @returns Promise with an array of task function responses that will be fulfilled when the tasks are completed.
*/
readonly mapExecute: (data: Iterable<Data>, name?: string, transferList?: readonly TransferListItem[]) => Promise<Response[]>;
/**
* Removes a task function from this pool.
* @param name - The name of the task function.
* @returns `true` if the task function was removed, `false` otherwise.
*/
readonly removeTaskFunction: (name: string) => Promise<boolean>;
/**
* Sets the default task function in this pool.
* @param name - The name of the task function.
* @returns `true` if the default task function was set, `false` otherwise.
*/
readonly setDefaultTaskFunction: (name: string) => Promise<boolean>;
/**
* Sets the worker node tasks queue options in this pool.
* @param tasksQueueOptions - The worker node tasks queue options.
*/
readonly setTasksQueueOptions: (tasksQueueOptions: TasksQueueOptions) => void;
/**
* Sets the default worker choice strategy in this pool.
* @param workerChoiceStrategy - The default worker choice strategy.
* @param workerChoiceStrategyOptions - The worker choice strategy options.
*/
readonly setWorkerChoiceStrategy: (workerChoiceStrategy: WorkerChoiceStrategy, workerChoiceStrategyOptions?: WorkerChoiceStrategyOptions) => void;
/**
* Sets the worker choice strategy options in this pool.
* @param workerChoiceStrategyOptions - The worker choice strategy options.
* @returns `true` if the worker choice strategy options were set, `false` otherwise.
*/
readonly setWorkerChoiceStrategyOptions: (workerChoiceStrategyOptions: WorkerChoiceStrategyOptions) => boolean;
/**
* Starts the minimum number of workers in this pool.
*/
readonly start: () => void;
/**
* Pool worker nodes.
* @internal
*/
readonly workerNodes: IWorkerNode<Worker, Data>[];
}
/**
* The worker choice strategies context.
* @typeParam Worker - Type of worker.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
* @internal
*/
declare class WorkerChoiceStrategiesContext<Worker extends IWorker, Data = unknown, Response = unknown> {
private readonly pool;
/**
* The default worker choice strategy in the context.
*/
private defaultWorkerChoiceStrategy;
/**
* The maximum number of worker choice strategies execution retries.
*/
private readonly retries;
/**
* The worker choice strategies registered in the context.
*/
private readonly workerChoiceStrategies;
/**
* The active worker choice strategies in the context policy.
*/
private workerChoiceStrategiesPolicy;
/**
* The active worker choice strategies in the context task statistics requirements.
*/
private workerChoiceStrategiesTaskStatisticsRequirements;
/**
* The number of worker choice strategies execution retries.
*/
retriesCount: number;
/**
* Worker choice strategies context constructor.
* @param pool - The pool instance.
* @param workerChoiceStrategies - The worker choice strategies. @defaultValue [WorkerChoiceStrategies.ROUND_ROBIN]
* @param opts - The worker choice strategy options.
*/
constructor(pool: IPool<Worker, Data, Response>, workerChoiceStrategies?: WorkerChoiceStrategy[], opts?: WorkerChoiceStrategyOptions);
/**
* Adds a worker choice strategy to the context.
* @param workerChoiceStrategy - The worker choice strategy to add.
* @param pool - The pool instance.
* @param opts - The worker choice strategy options.
* @returns The worker choice strategies.
*/
private addWorkerChoiceStrategy;
/**
* Executes the given worker choice strategy.
* @param workerChoiceStrategy - The worker choice strategy.
* @returns The key of the worker node.
* @throws {@link https://nodejs.org/api/errors.html#class-error} If after computed retries the worker node key is null or undefined.
*/
private executeStrategy;
/**
* Removes a worker choice strategy from the context.
* @param workerChoiceStrategy - The worker choice strategy to remove.
* @returns `true` if the worker choice strategy is removed, `false` otherwise.
*/
private removeWorkerChoiceStrategy;
/**
* Executes the given worker choice strategy in the context algorithm.
* @param workerChoiceStrategy - The worker choice strategy algorithm to execute. @defaultValue this.defaultWorkerChoiceStrategy
* @returns The key of the worker node.
* @throws {@link https://nodejs.org/api/errors.html#class-error} If after computed retries the worker node key is null or undefined.
*/
execute(workerChoiceStrategy?: WorkerChoiceStrategy): number;
/**
* Gets the active worker choice strategies in the context policy.
* @returns The strategies policy.
*/
getPolicy(): StrategyPolicy;
/**
* Gets the active worker choice strategies in the context task statistics requirements.
* @returns The strategies task statistics requirements.
*/
getTaskStatisticsRequirements(): TaskStatisticsRequirements;
/**
* Removes the worker node key from the active worker choice strategies in the context.
* @param workerNodeKey - The worker node key.
* @returns `true` if the removal is successful, `false` otherwise.
*/
remove(workerNodeKey: number): boolean;
/**
* Sets the default worker choice strategy to use in the context.
* @param workerChoiceStrategy - The default worker choice strategy to set.
* @param opts - The worker choice strategy options.
*/
setDefaultWorkerChoiceStrategy(workerChoiceStrategy: WorkerChoiceStrategy, opts?: WorkerChoiceStrategyOptions): void;
/**
* Sets the active worker choice strategies in the context options.
* @param opts - The worker choice strategy options.
*/
setOptions(opts: undefined | WorkerChoiceStrategyOptions): void;
/**
* Synchronizes the active worker choice strategies in the context with the given worker choice strategies.
* @param workerChoiceStrategies - The worker choice strategies to synchronize.
* @param opts - The worker choice strategy options.
*/
syncWorkerChoiceStrategies(workerChoiceStrategies: Set<WorkerChoiceStrategy>, opts?: WorkerChoiceStrategyOptions): void;
/**
* Updates the worker node key in the active worker choice strategies in the context internals.
* @param workerNodeKey - The worker node key.
* @returns `true` if the update is successful, `false` otherwise.
*/
update(workerNodeKey: number): boolean;
}
/**
* Base class that implements some shared logic for all poolifier pools.
* @typeParam Worker - Type of worker which manages this pool.
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
*/
declare abstract class AbstractPool<Worker extends IWorker, Data = unknown, Response = unknown> implements IPool<Worker, Data, Response> {
protected readonly minimumNumberOfWorkers: number;
protected readonly filePath: string;
protected readonly opts: PoolOptions<Worker>;
protected readonly maximumNumberOfWorkers?: number | undefined;
/**
* The task execution response promise map:
* - `key`: The message id of each submitted task.
* - `value`: An object that contains task's worker node key, execution response promise resolve and reject callbacks, async resource.
*
* When we receive a message from the worker, we get a map entry with the promise resolve/reject bound to the message id.
*/
protected promiseResponseMap: Map<`${string}-${string}-${string}-${string}-${string}`, PromiseResponseWrapper<Response>>;
/**
* Worker choice strategies context referencing worker choice algorithms implementation.
*/
protected workerChoiceStrategiesContext?: WorkerChoiceStrategiesContext<Worker, Data, Response>;
/**
* This method is the message listener registered on each worker.
* @param message - The message received from the worker.
*/
protected readonly workerMessageListener: (message: MessageValue<Response>) => void;
/**
* Whether the pool back pressure event has been emitted or not.
*/
private backPressureEventEmitted;
/**
* Whether the pool busy event has been emitted or not.
*/
private busyEventEmitted;
/**
* Whether the pool is destroying or not.
*/
private destroying;
/**
* Gets task function worker choice strategy, if any.
* @param name - The task function name.
* @returns The task function worker choice strategy if the task function worker choice strategy is defined, `undefined` otherwise.
*/
private readonly getTaskFunctionWorkerChoiceStrategy;
/**
* Gets the worker choice strategies registered in this pool.
* @returns The worker choice strategies.
*/
private readonly getWorkerChoiceStrategies;
/**
* Gets worker node task function priority, if any.
* @param workerNodeKey - The worker node key.
* @param name - The task function name.
* @returns The worker node task function priority if the worker node task function priority is defined, `undefined` otherwise.
*/
private readonly getWorkerNodeTaskFunctionPriority;
/**
* Gets worker node task function worker choice strategy, if any.
* @param workerNodeKey - The worker node key.
* @param name - The task function name.
* @returns The worker node task function worker choice strategy if the worker node task function worker choice strategy is defined, `undefined` otherwise.
*/
private readonly getWorkerNodeTaskFunctionWorkerChoiceStrategy;
private readonly handleWorkerNodeBackPressureEvent;
private readonly handleWorkerNodeIdleEvent;
private readonly isStealingRatioReached;
/**
* Whether the pool ready event has been emitted or not.
*/
private readyEventEmitted;
/**
* Whether the pool is started or not.
*/
private started;
/**
* Whether the pool is starting or not.
*/
private starting;
/**
* Whether the minimum number of workers is starting or not.
*/
private startingMinimumNumberOfWorkers;
/**
* The start timestamp of the pool.
*/
private startTimestamp?;
private readonly stealTask;
/**
* The task functions added at runtime map:
* - `key`: The task function name.
* - `value`: The task function object.
*/
private readonly taskFunctions;
private readonly workerNodeStealTask;
/** @inheritDoc */
emitter?: EventEmitterAsyncResource;
/** @inheritDoc */
readonly workerNodes: IWorkerNode<Worker, Data>[];
/**
* Constructs a new poolifier pool.
* @param minimumNumberOfWorkers - Minimum number of workers that this pool manages.
* @param filePath - Path to the worker file.
* @param opts - Options for the pool.
* @param maximumNumberOfWorkers - Maximum number of workers that this pool manages.
*/
constructor(minimumNumberOfWorkers: number, filePath: string, opts: PoolOptions<Worker>, maximumNumberOfWorkers?: number | undefined);
/**
* Hook executed after the worker task execution.
* Can be overridden.
* @param workerNodeKey - The worker node key.
* @param message - The received message.
*/
protected afterTaskExecutionHook(workerNodeKey: number, message: MessageValue<Response>): void;
/**
* Method hooked up after a worker node has been newly created.
* Can be overridden.
* @param workerNodeKey - The newly created worker node key.
*/
protected afterWorkerNodeSetup(workerNodeKey: number): void;
/**
* Hook executed before the worker task execution.
* Can be overridden.
* @param workerNodeKey - The worker node key.
* @param task - The task to execute.
*/
protected beforeTaskExecutionHook(workerNodeKey: number, task: Task<Data>): void;
/**
* Emits dynamic worker creation events.
*/
protected abstract checkAndEmitDynamicWorkerCreationEvents(): void;
/**
* Emits dynamic worker destruction events.
*/
protected abstract checkAndEmitDynamicWorkerDestructionEvents(): void;
/**
* Creates a new, completely set up dynamic worker node.
* @returns New, completely set up dynamic worker node key.
*/
protected createAndSetupDynamicWorkerNode(): number;
/**
* Creates a new, completely set up worker node.
* @returns New, completely set up worker node key.
*/
protected createAndSetupWorkerNode(): number;
/**
* Deregisters a listener callback on the worker given its worker node key.
* @param workerNodeKey - The worker node key.
* @param listener - The message listener callback.
*/
protected abstract deregisterWorkerMessageListener<Message extends Data | Response>(workerNodeKey: number, listener: (message: MessageValue<Message>) => void): void;
/**
* Terminates the worker node given its worker node key.
* @param workerNodeKey - The worker node key.
*/
protected destroyWorkerNode(workerNodeKey: number): Promise<void>;
protected flagWorkerNodeAsNotReady(workerNodeKey: number): void;
protected flushTasksQueue(workerNodeKey: number): number;
/**
* Gets the worker information given its worker node key.
* @param workerNodeKey - The worker node key.
* @returns The worker information.
*/
protected getWorkerI