poolifier
Version:
Fast and small Node.js Worker_Threads and Cluster Worker Pool
1,506 lines (1,496 loc) • 86.9 kB
TypeScript
import { Transferable, 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 numbers.
* @internal
*/
declare class CircularBuffer {
size: number;
private readonly items;
private readonly maxArrayIdx;
private readIdx;
private writeIdx;
/**
* CircularBuffer constructor.
* @param size - Buffer size.
* @defaultValue defaultBufferSize
* @returns CircularBuffer.
*/
constructor(size?: number);
/**
* Clears the buffer.
*/
clear(): void;
/**
* 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[];
/**
* Checks the buffer size.
* @param size - Buffer size.
*/
private checkSize;
}
/**
* 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';
}>;
/**
* Worker choice strategy interface.
* @internal
*/
interface IWorkerChoiceStrategy {
/**
* Chooses a worker node in the pool and returns its key.
* If no worker nodes are eligible, `undefined` is returned and the caller retries.
* @param workerNodeKeysSet - The worker node keys affinity set. If undefined, all workers are eligible.
* @returns The worker node key or `undefined`.
*/
readonly choose: (workerNodeKeysSet?: ReadonlySet<number>) => number | undefined;
/**
* The worker choice strategy name.
*/
readonly name: WorkerChoiceStrategy;
/**
* 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;
/**
* The worker choice strategy execution retries count.
*/
retriesCount: number;
/**
* 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;
}
/**
* Measurement.
*/
type Measurement = keyof typeof Measurements;
/**
* Measurement options.
*/
interface MeasurementOptions {
/**
* Set measurement median.
*/
readonly median: boolean;
}
/**
* Measurement statistics requirements.
* @internal
*/
interface MeasurementStatisticsRequirements {
/**
* Requires measurement aggregate.
*/
aggregate: boolean;
/**
* Requires measurement average.
*/
average: boolean;
/**
* Requires measurement median.
*/
median: boolean;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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>;
}
/**
* 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;
}
/**
* Message object that is passed between main worker and worker.
* @template Data - Type of data sent to the worker or execution response. This can only be structured-cloneable data.
* @template 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 operation:
* - `'abort'` - Abort a task.
*/
readonly taskOperation?: 'abort';
/**
* 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.
* @template Response - Type of execution response. This can only be structured-cloneable data.
* @internal
*/
interface PromiseResponseWrapper<Response = unknown> {
/**
* The task abort signal.
*/
readonly abortSignal?: AbortSignal;
/**
* 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;
}
/**
* Message object that is passed as a task between main worker and worker.
* @template Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @internal
*/
interface Task<Data = unknown> {
/**
* Whether the task is abortable or not.
*/
readonly abortable?: boolean;
/**
* 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 Transferable[];
}
/**
* 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;
/**
* Task function worker node keys affinity.
* Restricts task execution to specified worker nodes by their indices.
* Must contain valid indices within [0, pool max size - 1].
* If undefined, task can execute on any worker node.
*/
readonly workerNodeKeys?: number[];
}
/**
* 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 error.
* @template Data - Type of data sent to the worker triggering an error. This can only be structured-cloneable data.
*/
interface WorkerError<Data = unknown> {
/**
* Whether the error is an abort error or not.
*/
readonly aborted: boolean;
/**
* 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;
}
/**
* 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;
}
/**
* Remove readonly modifier from all properties of T.
* @template T - Type to remove readonly modifier.
* @internal
*/
type Writable<T> = {
-readonly [P in keyof T]: T[P];
};
/**
* Task asynchronous function that can be executed.
* This function must return a promise.
* @param data - Data sent to the worker.
* @returns Execution response promise.
* @template Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @template 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.
* @template Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @template 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.
* @template Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @template 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>;
/**
* Task function worker node keys affinity.
* Restricts task execution to specified worker nodes by their indices.
* Must contain valid indices within [0, pool max size - 1].
* If undefined, task can execute on any worker node.
*/
workerNodeKeys?: number[];
}
/**
* Task function operation result.
*/
interface TaskFunctionOperationResult {
error?: Error;
status: boolean;
}
/**
* 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.
* @template Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @template 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 synchronous function that can be executed.
* @param data - Data sent to the worker.
* @returns Execution response.
* @template Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @template Response - Type of execution response. This can only be structured-cloneable data.
*/
type TaskSyncFunction<Data = unknown, Response = unknown> = (data?: Data) => Response;
/**
* Priority queue.
* @template T - Type of priority queue data.
* @internal
*/
declare class PriorityQueue<T> {
/** The priority queue maximum size. */
maxSize: number;
/** The priority queue size. */
size: number;
/**
* The number of filled prioritized buckets.
* @returns The number of filled prioritized buckets.
*/
get buckets(): number;
/**
* Whether priority is enabled.
* @returns Whether priority is enabled.
*/
get enablePriority(): boolean;
/**
* Enables/disables priority.
* @param enablePriority - Whether to enable priority.
*/
set enablePriority(enablePriority: boolean);
private readonly agingFactor;
private readonly bucketSize;
private head;
private readonly loadExponent;
private priorityEnabled;
private tail;
/**
* Constructs a priority queue.
* @param bucketSize - Prioritized bucket size.
* @defaultValue defaultBucketSize
* @param enablePriority - Whether to enable priority.
* @defaultValue false
* @param agingFactor - Aging factor for priority boosting (priority points per millisecond).
* @defaultValue defaultAgingFactor
* @param loadExponent - Load exponent for aging adjustment based on queue fill ratio.
* @defaultValue defaultLoadExponent
* @returns PriorityQueue.
*/
constructor(bucketSize?: number, enablePriority?: boolean, agingFactor?: number, loadExponent?: number);
/**
* Clears the priority queue.
*/
clear(): void;
/**
* Deletes the given data from the priority queue.
* @param data - Data to delete.
* @returns `true` if the data was deleted, `false` otherwise.
*/
delete(data: T): boolean;
/**
* Dequeue data from the priority queue.
* @param bucket - The prioritized bucket to dequeue from.
* @returns The dequeued data or `undefined` if the priority queue is empty.
*/
dequeue(bucket?: number): T | undefined;
/**
* Enqueue data into the priority queue.
* @param data - Data to enqueue.
* @param priority - Priority of the data. Lower values have higher priority.
* @returns The new size of the priority queue.
*/
enqueue(data: T, priority?: number): number;
/**
* Returns an iterator for the priority queue.
* @returns An iterator for the priority queue.
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
*/
[Symbol.iterator](): Iterator<T>;
private getPriorityQueueNode;
private removePriorityQueueNode;
}
/**
* Callback invoked if the worker raised an error.
* @template Worker - Type of worker.
*/
type ErrorHandler<Worker extends IWorker> = (this: Worker, error: Error) => void;
/**
* Worker event handler.
* @template Worker - Type of worker.
*/
type EventHandler<Worker extends IWorker> = ErrorHandler<Worker> | ExitHandler<Worker> | MessageHandler<Worker> | OnlineHandler<Worker>;
/**
* Callback invoked when the worker exits successfully.
* @template Worker - Type of worker.
*/
type ExitHandler<Worker extends IWorker> = (this: Worker, exitCode: number) => void;
/**
* Callback invoked if the worker has received a message.
* @template Worker - Type of worker.
*/
type MessageHandler<Worker extends IWorker> = (this: Worker, message: unknown) => void;
/**
* Callback invoked when the worker has started successfully.
* @template Worker - Type of worker.
*/
type OnlineHandler<Worker extends IWorker> = (this: Worker) => void;
/**
* Event loop utilization measurement statistics.
* @internal
*/
interface EventLoopUtilizationMeasurementStatistics {
readonly active: MeasurementStatistics;
count?: number;
readonly idle: MeasurementStatistics;
utilization?: number;
}
/**
* 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;
}
/**
* 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 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 interface.
* @template Worker - Type of worker.
* @template 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 a task from the tasks queue.
* @param task - The task to delete.
* @returns `true` if the task was deleted, `false` otherwise.
*/
readonly deleteTask: (task: Task<Data>) => boolean;
/**
* 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.
*/
readonly tasksQueue: PriorityQueue<Task<Data>>;
/**
* 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 choice strategy data.
* @internal
*/
interface StrategyData {
virtualTaskEndTimestamp?: number;
}
/**
* 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;
/**
* Queued task abortion flag.
* This flag is set to `true` when worker node is aborting a queued task.
*/
queuedTaskAbortion: boolean;
/**
* 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 node event detail.
* @internal
*/
interface WorkerNodeEventDetail {
taskId?: `${string}-${string}-${string}-${string}-${string}`;
workerId?: number;
workerNodeKey?: number;
}
/**
* Worker node options.
* @internal
*/
interface WorkerNodeOptions {
env?: Record<string, unknown>;
tasksQueueAgingFactor: number | undefined;
tasksQueueBackPressureSize: number | undefined;
tasksQueueBucketSize: number | undefined;
tasksQueueLoadExponent: number | undefined;
tasksQueuePriority: boolean | undefined;
workerOptions?: WorkerOptions$1;
}
/**
* Worker type.
*/
type WorkerType = keyof typeof WorkerTypes;
/**
* 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;
}
/**
* 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';
}>;
/**
* Contract definition for a poolifier pool.
* @template Worker - Type of worker which manages this pool.
* @template Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @template 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 {TypeError} If the `name` parameter is not a string or an empty string.
* @throws {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 abortSignal - The optional AbortSignal to abort the task.
* @param transferList - The 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, abortSignal?: AbortSignal, transferList?: readonly Transferable[]) => 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 abortSignals - The optional iterable of AbortSignal to abort the tasks iterable.
* @param transferList - The 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, abortSignals?: Iterable<AbortSignal>, transferList?: readonly Transferable[]) => 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>[];
}
/**
* 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;
}
/**
* Options for a poolifier pool.
* @template 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.LEAST_USED
*/
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;
}
/**
* Worker node tasks queue options.
*/
interface TasksQueueOptions {
/**
* Controls the priority queue anti-starvation aging rate.
* @defaultValue 0.001
*/
readonly agingFactor?: number;
/**
* Maximum number of tasks that can be executed concurrently on a worker node.
* @defaultValue 1
*/
readonly concurrency?: number;
/**
* Controls load-based aging adjustment exponent.
* @defaultValue 0.667
*/
readonly loadExponent?: 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;
}
/**
* The worker choice strategies context.
* @template Worker - Type of worker.
* @template Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @template 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 strategy 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;
/**
* Worker choice strategies context constructor.
* @param pool - The pool instance.
* @param workerChoiceStrategies - The worker choice strategies.
* @defaultValue [WorkerChoiceStrategies.LEAST_USED]
* @param opts - The worker choice strategy options.
*/
constructor(pool: IPool<Worker, Data, Response>, workerChoiceStrategies?: WorkerChoiceStrategy[], opts?: WorkerChoiceStrategyOptions);
/**
* Executes the given worker choice strategy.
* @param workerChoiceStrategy - The worker choice strategy.
* @param workerNodeKeysSet - The worker node keys affinity set. If undefined, all workers are eligible.
* @returns The key of the worker node.
* @throws {Error} If after computed retries the worker node key is null or undefined.
*/
execute(workerChoiceStrategy?: WorkerChoiceStrategy, workerNodeKeysSet?: ReadonlySet<number>): number;
/**
* Gets the active worker choice strategies in the context policy.
* @returns The strategies policy.
*/
getPolicy(): StrategyPolicy;
/**
* Gets the number of worker choice strategies execution retries.
* @returns The number of retries.
*/
getStrategyRetries(): number;
/**
* 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;
/**
* 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 in the context algorithm.
* @param workerChoiceStrategy - The worker choice strategy algorithm to execute.
* @param workerNodeKeysSet - The worker node keys affinity set. If undefined, all workers are eligible.
* @returns The key of the worker node.
* @throws {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;
}
/**
* Base class that implements some shared logic for all poolifier pools.
* @template Worker - Type of worker which manages this pool.
* @template Data - Type of data sent to the worker. This can only be structured-cloneable data.
* @template 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;
/** @inheritDoc */
emitter?: EventEmitterAsyncResource;
/** @inheritDoc */
readonly workerNodes: IWorkerNode<Worker, Data>[];
/** @inheritDoc */
get info(): PoolInfo;
/**
* Whether the pool is destroying or not.
*/
protected destroying: boolean;
/**
* 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>>;
/**
* Whether the pool is started or not.
*/
protected started: boolean;
/**
* Whether the pool is starting or not.
*/
protected starting: boolean;
/**
* Worker choice strategies context referencing worker choice algorithms implementation.
*/
protected workerChoiceStrategiesContext?: WorkerChoiceStrategiesC