poolifier 2.6.45 → 2.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +167 -73
- package/lib/index.js +1 -1
- package/lib/index.mjs +1 -1
- package/package.json +5 -5
package/lib/index.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ interface WorkerOptions {
|
|
|
42
42
|
*/
|
|
43
43
|
killBehavior?: KillBehavior;
|
|
44
44
|
/**
|
|
45
|
-
* Maximum waiting time in milliseconds for tasks on newly created workers.
|
|
45
|
+
* Maximum waiting time in milliseconds for tasks on newly created workers. It must be greater or equal than 5.
|
|
46
46
|
*
|
|
47
47
|
* After this time, newly created workers will be terminated.
|
|
48
48
|
* The last active time of your worker will be updated when it terminates a task.
|
|
@@ -56,6 +56,8 @@ interface WorkerOptions {
|
|
|
56
56
|
maxInactiveTime?: number;
|
|
57
57
|
/**
|
|
58
58
|
* The function to call when a worker is killed.
|
|
59
|
+
*
|
|
60
|
+
* @defaultValue `() => {}`
|
|
59
61
|
*/
|
|
60
62
|
killHandler?: KillHandler;
|
|
61
63
|
/**
|
|
@@ -68,13 +70,13 @@ interface WorkerOptions {
|
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
/**
|
|
71
|
-
*
|
|
73
|
+
* Worker error.
|
|
72
74
|
*
|
|
73
75
|
* @typeParam Data - Type of data sent to the worker triggering an error. This can only be structured-cloneable data.
|
|
74
76
|
*/
|
|
75
|
-
interface
|
|
77
|
+
interface WorkerError<Data = unknown> {
|
|
76
78
|
/**
|
|
77
|
-
* Task name triggering the error.
|
|
79
|
+
* Task function name triggering the error.
|
|
78
80
|
*/
|
|
79
81
|
readonly name: string;
|
|
80
82
|
/**
|
|
@@ -134,7 +136,7 @@ interface Task<Data = unknown> {
|
|
|
134
136
|
/**
|
|
135
137
|
* Worker id.
|
|
136
138
|
*/
|
|
137
|
-
readonly workerId
|
|
139
|
+
readonly workerId?: number;
|
|
138
140
|
/**
|
|
139
141
|
* Task name.
|
|
140
142
|
*/
|
|
@@ -169,17 +171,36 @@ interface MessageValue<Data = unknown, ErrorData = unknown> extends Task<Data> {
|
|
|
169
171
|
*/
|
|
170
172
|
readonly kill?: KillBehavior | true | 'success' | 'failure';
|
|
171
173
|
/**
|
|
172
|
-
*
|
|
174
|
+
* Worker error.
|
|
173
175
|
*/
|
|
174
|
-
readonly
|
|
176
|
+
readonly workerError?: WorkerError<ErrorData>;
|
|
175
177
|
/**
|
|
176
178
|
* Task performance.
|
|
177
179
|
*/
|
|
178
180
|
readonly taskPerformance?: TaskPerformance;
|
|
181
|
+
/**
|
|
182
|
+
* Task function operation:
|
|
183
|
+
* - `'add'` - Add a task function.
|
|
184
|
+
* - `'remove'` - Remove a task function.
|
|
185
|
+
* - `'default'` - Set a task function as default.
|
|
186
|
+
*/
|
|
187
|
+
readonly taskFunctionOperation?: 'add' | 'remove' | 'default';
|
|
188
|
+
/**
|
|
189
|
+
* Whether the task function operation is successful or not.
|
|
190
|
+
*/
|
|
191
|
+
readonly taskFunctionOperationStatus?: boolean;
|
|
192
|
+
/**
|
|
193
|
+
* Task function serialized to string.
|
|
194
|
+
*/
|
|
195
|
+
readonly taskFunction?: string;
|
|
196
|
+
/**
|
|
197
|
+
* Task function name.
|
|
198
|
+
*/
|
|
199
|
+
readonly taskFunctionName?: string;
|
|
179
200
|
/**
|
|
180
201
|
* Task function names.
|
|
181
202
|
*/
|
|
182
|
-
readonly
|
|
203
|
+
readonly taskFunctionNames?: string[];
|
|
183
204
|
/**
|
|
184
205
|
* Whether the worker computes the given statistics or not.
|
|
185
206
|
*/
|
|
@@ -221,6 +242,47 @@ type Writable<T> = {
|
|
|
221
242
|
-readonly [P in keyof T]: T[P];
|
|
222
243
|
};
|
|
223
244
|
|
|
245
|
+
/**
|
|
246
|
+
* Task synchronous function that can be executed.
|
|
247
|
+
*
|
|
248
|
+
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
|
|
249
|
+
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
|
|
250
|
+
*/
|
|
251
|
+
type TaskSyncFunction<Data = unknown, Response = unknown> = (data?: Data) => Response;
|
|
252
|
+
/**
|
|
253
|
+
* Task asynchronous function that can be executed.
|
|
254
|
+
* This function must return a promise.
|
|
255
|
+
*
|
|
256
|
+
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
|
|
257
|
+
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
|
|
258
|
+
*/
|
|
259
|
+
type TaskAsyncFunction<Data = unknown, Response = unknown> = (data?: Data) => Promise<Response>;
|
|
260
|
+
/**
|
|
261
|
+
* Task function that can be executed.
|
|
262
|
+
* This function can be synchronous or asynchronous.
|
|
263
|
+
*
|
|
264
|
+
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
|
|
265
|
+
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
|
|
266
|
+
*/
|
|
267
|
+
type TaskFunction<Data = unknown, Response = unknown> = TaskSyncFunction<Data, Response> | TaskAsyncFunction<Data, Response>;
|
|
268
|
+
/**
|
|
269
|
+
* Tasks functions that can be executed.
|
|
270
|
+
* This object can contain synchronous or asynchronous functions.
|
|
271
|
+
* The key is the name of the function.
|
|
272
|
+
* The value is the function itself.
|
|
273
|
+
*
|
|
274
|
+
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
|
|
275
|
+
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
|
|
276
|
+
*/
|
|
277
|
+
type TaskFunctions<Data = unknown, Response = unknown> = Record<string, TaskFunction<Data, Response>>;
|
|
278
|
+
/**
|
|
279
|
+
* Task function operation result.
|
|
280
|
+
*/
|
|
281
|
+
interface TaskFunctionOperationResult {
|
|
282
|
+
status: boolean;
|
|
283
|
+
error?: Error;
|
|
284
|
+
}
|
|
285
|
+
|
|
224
286
|
/**
|
|
225
287
|
* Array with a maximum length and shifting items when full.
|
|
226
288
|
*
|
|
@@ -367,7 +429,7 @@ interface WorkerInfo {
|
|
|
367
429
|
/**
|
|
368
430
|
* Task function names.
|
|
369
431
|
*/
|
|
370
|
-
|
|
432
|
+
taskFunctionNames?: string[];
|
|
371
433
|
}
|
|
372
434
|
/**
|
|
373
435
|
* Worker usage statistics.
|
|
@@ -530,6 +592,13 @@ interface IWorkerNode<Worker extends IWorker, Data = unknown> {
|
|
|
530
592
|
* @returns The task function worker usage statistics if the task function worker usage statistics are initialized, `undefined` otherwise.
|
|
531
593
|
*/
|
|
532
594
|
readonly getTaskFunctionWorkerUsage: (name: string) => WorkerUsage | undefined;
|
|
595
|
+
/**
|
|
596
|
+
* Deletes task function worker usage statistics.
|
|
597
|
+
*
|
|
598
|
+
* @param name - The task function name.
|
|
599
|
+
* @returns `true` if the task function worker usage statistics were deleted, `false` otherwise.
|
|
600
|
+
*/
|
|
601
|
+
readonly deleteTaskFunctionWorkerUsage: (name: string) => boolean;
|
|
533
602
|
}
|
|
534
603
|
|
|
535
604
|
/**
|
|
@@ -964,12 +1033,44 @@ interface IPool<Worker extends IWorker, Data = unknown, Response = unknown> {
|
|
|
964
1033
|
* Terminates all workers in this pool.
|
|
965
1034
|
*/
|
|
966
1035
|
readonly destroy: () => Promise<void>;
|
|
1036
|
+
/**
|
|
1037
|
+
* Whether the specified task function exists in this pool.
|
|
1038
|
+
*
|
|
1039
|
+
* @param name - The name of the task function.
|
|
1040
|
+
* @returns `true` if the task function exists, `false` otherwise.
|
|
1041
|
+
*/
|
|
1042
|
+
readonly hasTaskFunction: (name: string) => boolean;
|
|
1043
|
+
/**
|
|
1044
|
+
* Adds a task function to this pool.
|
|
1045
|
+
* If a task function with the same name already exists, it will be overwritten.
|
|
1046
|
+
*
|
|
1047
|
+
* @param name - The name of the task function.
|
|
1048
|
+
* @param fn - The task function.
|
|
1049
|
+
* @returns `true` if the task function was added, `false` otherwise.
|
|
1050
|
+
* @throws {@link https://nodejs.org/api/errors.html#class-typeerror} If the `name` parameter is not a string or an empty string.
|
|
1051
|
+
* @throws {@link https://nodejs.org/api/errors.html#class-typeerror} If the `fn` parameter is not a function.
|
|
1052
|
+
*/
|
|
1053
|
+
readonly addTaskFunction: (name: string, fn: TaskFunction<Data, Response>) => Promise<boolean>;
|
|
1054
|
+
/**
|
|
1055
|
+
* Removes a task function from this pool.
|
|
1056
|
+
*
|
|
1057
|
+
* @param name - The name of the task function.
|
|
1058
|
+
* @returns `true` if the task function was removed, `false` otherwise.
|
|
1059
|
+
*/
|
|
1060
|
+
readonly removeTaskFunction: (name: string) => Promise<boolean>;
|
|
967
1061
|
/**
|
|
968
1062
|
* Lists the names of task function available in this pool.
|
|
969
1063
|
*
|
|
970
1064
|
* @returns The names of task function available in this pool.
|
|
971
1065
|
*/
|
|
972
|
-
readonly
|
|
1066
|
+
readonly listTaskFunctionNames: () => string[];
|
|
1067
|
+
/**
|
|
1068
|
+
* Sets the default task function in this pool.
|
|
1069
|
+
*
|
|
1070
|
+
* @param name - The name of the task function.
|
|
1071
|
+
* @returns `true` if the default task function was set, `false` otherwise.
|
|
1072
|
+
*/
|
|
1073
|
+
readonly setDefaultTaskFunction: (name: string) => Promise<boolean>;
|
|
973
1074
|
/**
|
|
974
1075
|
* Sets the worker choice strategy in this pool.
|
|
975
1076
|
*
|
|
@@ -1098,6 +1199,12 @@ declare abstract class AbstractPool<Worker extends IWorker, Data = unknown, Resp
|
|
|
1098
1199
|
* Dynamic pool maximum size property placeholder.
|
|
1099
1200
|
*/
|
|
1100
1201
|
protected readonly max?: number;
|
|
1202
|
+
/**
|
|
1203
|
+
* The task functions added at runtime map:
|
|
1204
|
+
* - `key`: The task function name.
|
|
1205
|
+
* - `value`: The task function itself.
|
|
1206
|
+
*/
|
|
1207
|
+
private readonly taskFunctions;
|
|
1101
1208
|
/**
|
|
1102
1209
|
* Whether the pool is started or not.
|
|
1103
1210
|
*/
|
|
@@ -1118,13 +1225,9 @@ declare abstract class AbstractPool<Worker extends IWorker, Data = unknown, Resp
|
|
|
1118
1225
|
* @param opts - Options for the pool.
|
|
1119
1226
|
*/
|
|
1120
1227
|
constructor(numberOfWorkers: number, filePath: string, opts: PoolOptions<Worker>);
|
|
1121
|
-
private checkFilePath;
|
|
1122
1228
|
private checkNumberOfWorkers;
|
|
1123
|
-
protected checkDynamicPoolSize(min: number, max: number): void;
|
|
1124
1229
|
private checkPoolOptions;
|
|
1125
|
-
private checkValidWorkerChoiceStrategy;
|
|
1126
1230
|
private checkValidWorkerChoiceStrategyOptions;
|
|
1127
|
-
private checkValidTasksQueueOptions;
|
|
1128
1231
|
/** @inheritDoc */
|
|
1129
1232
|
get info(): PoolInfo;
|
|
1130
1233
|
/**
|
|
@@ -1184,8 +1287,12 @@ declare abstract class AbstractPool<Worker extends IWorker, Data = unknown, Resp
|
|
|
1184
1287
|
enableTasksQueue(enable: boolean, tasksQueueOptions?: TasksQueueOptions): void;
|
|
1185
1288
|
/** @inheritDoc */
|
|
1186
1289
|
setTasksQueueOptions(tasksQueueOptions: TasksQueueOptions): void;
|
|
1187
|
-
private setTasksQueueSize;
|
|
1188
1290
|
private buildTasksQueueOptions;
|
|
1291
|
+
private setTasksQueueSize;
|
|
1292
|
+
private setTaskStealing;
|
|
1293
|
+
private unsetTaskStealing;
|
|
1294
|
+
private setTasksStealingOnBackPressure;
|
|
1295
|
+
private unsetTasksStealingOnBackPressure;
|
|
1189
1296
|
/**
|
|
1190
1297
|
* Whether the pool is full or not.
|
|
1191
1298
|
*
|
|
@@ -1204,8 +1311,19 @@ declare abstract class AbstractPool<Worker extends IWorker, Data = unknown, Resp
|
|
|
1204
1311
|
* @returns Worker nodes busyness boolean status.
|
|
1205
1312
|
*/
|
|
1206
1313
|
protected internalBusy(): boolean;
|
|
1314
|
+
private sendTaskFunctionOperationToWorker;
|
|
1315
|
+
private sendTaskFunctionOperationToWorkers;
|
|
1316
|
+
/** @inheritDoc */
|
|
1317
|
+
hasTaskFunction(name: string): boolean;
|
|
1318
|
+
/** @inheritDoc */
|
|
1319
|
+
addTaskFunction(name: string, fn: TaskFunction<Data, Response>): Promise<boolean>;
|
|
1207
1320
|
/** @inheritDoc */
|
|
1208
|
-
|
|
1321
|
+
removeTaskFunction(name: string): Promise<boolean>;
|
|
1322
|
+
/** @inheritDoc */
|
|
1323
|
+
listTaskFunctionNames(): string[];
|
|
1324
|
+
/** @inheritDoc */
|
|
1325
|
+
setDefaultTaskFunction(name: string): Promise<boolean>;
|
|
1326
|
+
private deleteTaskFunctionWorkerUsages;
|
|
1209
1327
|
private shallExecuteTask;
|
|
1210
1328
|
/** @inheritDoc */
|
|
1211
1329
|
execute(data?: Data, name?: string, transferList?: TransferListItem[]): Promise<Response>;
|
|
@@ -1213,7 +1331,7 @@ declare abstract class AbstractPool<Worker extends IWorker, Data = unknown, Resp
|
|
|
1213
1331
|
start(): void;
|
|
1214
1332
|
/** @inheritDoc */
|
|
1215
1333
|
destroy(): Promise<void>;
|
|
1216
|
-
protected sendKillMessageToWorker(workerNodeKey: number
|
|
1334
|
+
protected sendKillMessageToWorker(workerNodeKey: number): Promise<void>;
|
|
1217
1335
|
/**
|
|
1218
1336
|
* Terminates the worker node given its worker node key.
|
|
1219
1337
|
*
|
|
@@ -1305,6 +1423,20 @@ declare abstract class AbstractPool<Worker extends IWorker, Data = unknown, Resp
|
|
|
1305
1423
|
* @param listener - The message listener callback.
|
|
1306
1424
|
*/
|
|
1307
1425
|
protected abstract registerWorkerMessageListener<Message extends Data | Response>(workerNodeKey: number, listener: (message: MessageValue<Message>) => void): void;
|
|
1426
|
+
/**
|
|
1427
|
+
* Registers once a listener callback on the worker given its worker node key.
|
|
1428
|
+
*
|
|
1429
|
+
* @param workerNodeKey - The worker node key.
|
|
1430
|
+
* @param listener - The message listener callback.
|
|
1431
|
+
*/
|
|
1432
|
+
protected abstract registerOnceWorkerMessageListener<Message extends Data | Response>(workerNodeKey: number, listener: (message: MessageValue<Message>) => void): void;
|
|
1433
|
+
/**
|
|
1434
|
+
* Deregisters a listener callback on the worker given its worker node key.
|
|
1435
|
+
*
|
|
1436
|
+
* @param workerNodeKey - The worker node key.
|
|
1437
|
+
* @param listener - The message listener callback.
|
|
1438
|
+
*/
|
|
1439
|
+
protected abstract deregisterWorkerMessageListener<Message extends Data | Response>(workerNodeKey: number, listener: (message: MessageValue<Message>) => void): void;
|
|
1308
1440
|
/**
|
|
1309
1441
|
* Method hooked up after a worker node has been newly created.
|
|
1310
1442
|
* Can be overridden.
|
|
@@ -1425,6 +1557,10 @@ declare class FixedClusterPool<Data = unknown, Response = unknown> extends Abstr
|
|
|
1425
1557
|
/** @inheritDoc */
|
|
1426
1558
|
protected registerWorkerMessageListener<Message extends Data | Response>(workerNodeKey: number, listener: (message: MessageValue<Message>) => void): void;
|
|
1427
1559
|
/** @inheritDoc */
|
|
1560
|
+
protected registerOnceWorkerMessageListener<Message extends Data | Response>(workerNodeKey: number, listener: (message: MessageValue<Message>) => void): void;
|
|
1561
|
+
/** @inheritDoc */
|
|
1562
|
+
protected deregisterWorkerMessageListener<Message extends Data | Response>(workerNodeKey: number, listener: (message: MessageValue<Message>) => void): void;
|
|
1563
|
+
/** @inheritDoc */
|
|
1428
1564
|
protected createWorker(): Worker;
|
|
1429
1565
|
/** @inheritDoc */
|
|
1430
1566
|
protected get type(): PoolType;
|
|
@@ -1502,6 +1638,10 @@ declare class FixedThreadPool<Data = unknown, Response = unknown> extends Abstra
|
|
|
1502
1638
|
/** @inheritDoc */
|
|
1503
1639
|
protected registerWorkerMessageListener<Message extends Data | Response>(workerNodeKey: number, listener: (message: MessageValue<Message>) => void): void;
|
|
1504
1640
|
/** @inheritDoc */
|
|
1641
|
+
protected registerOnceWorkerMessageListener<Message extends Data | Response>(workerNodeKey: number, listener: (message: MessageValue<Message>) => void): void;
|
|
1642
|
+
/** @inheritDoc */
|
|
1643
|
+
protected deregisterWorkerMessageListener<Message extends Data | Response>(workerNodeKey: number, listener: (message: MessageValue<Message>) => void): void;
|
|
1644
|
+
/** @inheritDoc */
|
|
1505
1645
|
protected createWorker(): Worker$1;
|
|
1506
1646
|
/** @inheritDoc */
|
|
1507
1647
|
protected get type(): PoolType;
|
|
@@ -1539,40 +1679,6 @@ declare class DynamicThreadPool<Data = unknown, Response = unknown> extends Fixe
|
|
|
1539
1679
|
protected get busy(): boolean;
|
|
1540
1680
|
}
|
|
1541
1681
|
|
|
1542
|
-
/**
|
|
1543
|
-
* Task synchronous function that can be executed.
|
|
1544
|
-
*
|
|
1545
|
-
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
|
|
1546
|
-
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
|
|
1547
|
-
*/
|
|
1548
|
-
type TaskSyncFunction<Data = unknown, Response = unknown> = (data?: Data) => Response;
|
|
1549
|
-
/**
|
|
1550
|
-
* Task asynchronous function that can be executed.
|
|
1551
|
-
* This function must return a promise.
|
|
1552
|
-
*
|
|
1553
|
-
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
|
|
1554
|
-
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
|
|
1555
|
-
*/
|
|
1556
|
-
type TaskAsyncFunction<Data = unknown, Response = unknown> = (data?: Data) => Promise<Response>;
|
|
1557
|
-
/**
|
|
1558
|
-
* Task function that can be executed.
|
|
1559
|
-
* This function can be synchronous or asynchronous.
|
|
1560
|
-
*
|
|
1561
|
-
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
|
|
1562
|
-
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
|
|
1563
|
-
*/
|
|
1564
|
-
type TaskFunction<Data = unknown, Response = unknown> = TaskSyncFunction<Data, Response> | TaskAsyncFunction<Data, Response>;
|
|
1565
|
-
/**
|
|
1566
|
-
* Tasks functions that can be executed.
|
|
1567
|
-
* This object can contain synchronous or asynchronous functions.
|
|
1568
|
-
* The key is the name of the function.
|
|
1569
|
-
* The value is the function itself.
|
|
1570
|
-
*
|
|
1571
|
-
* @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
|
|
1572
|
-
* @typeParam Response - Type of execution response. This can only be structured-cloneable data.
|
|
1573
|
-
*/
|
|
1574
|
-
type TaskFunctions<Data = unknown, Response = unknown> = Record<string, TaskFunction<Data, Response>>;
|
|
1575
|
-
|
|
1576
1682
|
/**
|
|
1577
1683
|
* Base class that implements some shared logic for all poolifier workers.
|
|
1578
1684
|
*
|
|
@@ -1615,9 +1721,8 @@ declare abstract class AbstractWorker<MainWorker extends Worker | MessagePort, D
|
|
|
1615
1721
|
*/
|
|
1616
1722
|
constructor(type: string, isMain: boolean, mainWorker: MainWorker, taskFunctions: TaskFunction<Data, Response> | TaskFunctions<Data, Response>, opts?: WorkerOptions);
|
|
1617
1723
|
private checkWorkerOptions;
|
|
1618
|
-
private checkValidTaskFunction;
|
|
1619
1724
|
/**
|
|
1620
|
-
* Checks if the `taskFunctions` parameter is passed to the constructor.
|
|
1725
|
+
* Checks if the `taskFunctions` parameter is passed to the constructor and valid.
|
|
1621
1726
|
*
|
|
1622
1727
|
* @param taskFunctions - The task function(s) parameter that should be checked.
|
|
1623
1728
|
*/
|
|
@@ -1627,9 +1732,8 @@ declare abstract class AbstractWorker<MainWorker extends Worker | MessagePort, D
|
|
|
1627
1732
|
*
|
|
1628
1733
|
* @param name - The name of the task function to check.
|
|
1629
1734
|
* @returns Whether the worker has a task function with the given name or not.
|
|
1630
|
-
* @throws {@link https://nodejs.org/api/errors.html#class-typeerror} If the `name` parameter is not a string or an empty string.
|
|
1631
1735
|
*/
|
|
1632
|
-
hasTaskFunction(name: string):
|
|
1736
|
+
hasTaskFunction(name: string): TaskFunctionOperationResult;
|
|
1633
1737
|
/**
|
|
1634
1738
|
* Adds a task function to the worker.
|
|
1635
1739
|
* If a task function with the same name already exists, it is replaced.
|
|
@@ -1637,38 +1741,28 @@ declare abstract class AbstractWorker<MainWorker extends Worker | MessagePort, D
|
|
|
1637
1741
|
* @param name - The name of the task function to add.
|
|
1638
1742
|
* @param fn - The task function to add.
|
|
1639
1743
|
* @returns Whether the task function was added or not.
|
|
1640
|
-
* @throws {@link https://nodejs.org/api/errors.html#class-typeerror} If the `name` parameter is not a string or an empty string.
|
|
1641
|
-
* @throws {@link https://nodejs.org/api/errors.html#class-error} If the `name` parameter is the default task function reserved name.
|
|
1642
|
-
* @throws {@link https://nodejs.org/api/errors.html#class-typeerror} If the `fn` parameter is not a function.
|
|
1643
1744
|
*/
|
|
1644
|
-
addTaskFunction(name: string, fn: TaskFunction<Data, Response>):
|
|
1745
|
+
addTaskFunction(name: string, fn: TaskFunction<Data, Response>): TaskFunctionOperationResult;
|
|
1645
1746
|
/**
|
|
1646
1747
|
* Removes a task function from the worker.
|
|
1647
1748
|
*
|
|
1648
1749
|
* @param name - The name of the task function to remove.
|
|
1649
1750
|
* @returns Whether the task function existed and was removed or not.
|
|
1650
|
-
* @throws {@link https://nodejs.org/api/errors.html#class-typeerror} If the `name` parameter is not a string or an empty string.
|
|
1651
|
-
* @throws {@link https://nodejs.org/api/errors.html#class-error} If the `name` parameter is the default task function reserved name.
|
|
1652
|
-
* @throws {@link https://nodejs.org/api/errors.html#class-error} If the `name` parameter is the task function used as default task function.
|
|
1653
1751
|
*/
|
|
1654
|
-
removeTaskFunction(name: string):
|
|
1752
|
+
removeTaskFunction(name: string): TaskFunctionOperationResult;
|
|
1655
1753
|
/**
|
|
1656
1754
|
* Lists the names of the worker's task functions.
|
|
1657
1755
|
*
|
|
1658
1756
|
* @returns The names of the worker's task functions.
|
|
1659
1757
|
*/
|
|
1660
|
-
|
|
1758
|
+
listTaskFunctionNames(): string[];
|
|
1661
1759
|
/**
|
|
1662
1760
|
* Sets the default task function to use in the worker.
|
|
1663
1761
|
*
|
|
1664
1762
|
* @param name - The name of the task function to use as default task function.
|
|
1665
1763
|
* @returns Whether the default task function was set or not.
|
|
1666
|
-
* @throws {@link https://nodejs.org/api/errors.html#class-typeerror} If the `name` parameter is not a string or an empty string.
|
|
1667
|
-
* @throws {@link https://nodejs.org/api/errors.html#class-error} If the `name` parameter is the default task function reserved name.
|
|
1668
|
-
* @throws {@link https://nodejs.org/api/errors.html#class-error} If the `name` parameter is a non-existing task function.
|
|
1669
1764
|
*/
|
|
1670
|
-
setDefaultTaskFunction(name: string):
|
|
1671
|
-
private checkTaskFunctionName;
|
|
1765
|
+
setDefaultTaskFunction(name: string): TaskFunctionOperationResult;
|
|
1672
1766
|
/**
|
|
1673
1767
|
* Handles the ready message sent by the main worker.
|
|
1674
1768
|
*
|
|
@@ -1681,6 +1775,7 @@ declare abstract class AbstractWorker<MainWorker extends Worker | MessagePort, D
|
|
|
1681
1775
|
* @param message - The received message.
|
|
1682
1776
|
*/
|
|
1683
1777
|
protected messageListener(message: MessageValue<Data>): void;
|
|
1778
|
+
protected handleTaskFunctionOperationMessage(message: MessageValue<Data>): void;
|
|
1684
1779
|
/**
|
|
1685
1780
|
* Handles a kill message sent by the main worker.
|
|
1686
1781
|
*
|
|
@@ -1720,9 +1815,9 @@ declare abstract class AbstractWorker<MainWorker extends Worker | MessagePort, D
|
|
|
1720
1815
|
*/
|
|
1721
1816
|
protected abstract sendToMainWorker(message: MessageValue<Response, Data>): void;
|
|
1722
1817
|
/**
|
|
1723
|
-
* Sends
|
|
1818
|
+
* Sends task function names to the main worker.
|
|
1724
1819
|
*/
|
|
1725
|
-
protected
|
|
1820
|
+
protected sendTaskFunctionNamesToMainWorker(): void;
|
|
1726
1821
|
/**
|
|
1727
1822
|
* Handles an error and convert it to a string so it can be sent back to the main worker.
|
|
1728
1823
|
*
|
|
@@ -1734,7 +1829,6 @@ declare abstract class AbstractWorker<MainWorker extends Worker | MessagePort, D
|
|
|
1734
1829
|
* Runs the given task.
|
|
1735
1830
|
*
|
|
1736
1831
|
* @param task - The task to execute.
|
|
1737
|
-
* @throws {@link https://nodejs.org/api/errors.html#class-error} If the task function is not found.
|
|
1738
1832
|
*/
|
|
1739
1833
|
protected run(task: Task<Data>): void;
|
|
1740
1834
|
/**
|
|
@@ -1917,4 +2011,4 @@ declare class Deque<T> {
|
|
|
1917
2011
|
*/
|
|
1918
2012
|
declare const availableParallelism: () => number;
|
|
1919
2013
|
|
|
1920
|
-
export { AbstractPool, AbstractWorker, CircularArray, type ClusterPoolOptions, ClusterWorker, Deque, DynamicClusterPool, DynamicThreadPool, type ErrorHandler, type EventLoopUtilizationMeasurementStatistics, type ExitHandler, FixedClusterPool, FixedThreadPool, type IPool, type IWorker, type IWorkerChoiceStrategy, type IWorkerNode, type KillBehavior, KillBehaviors, type KillHandler, type Measurement, type MeasurementOptions, type MeasurementStatistics, type MeasurementStatisticsRequirements, Measurements, type MessageHandler, type MessageValue, Node, type OnlineHandler, PoolEmitter, type PoolEvent, PoolEvents, type PoolInfo, type PoolOptions, type PoolType, PoolTypes, type PromiseResponseWrapper, type StrategyData, type StrategyPolicy, type Task, type TaskAsyncFunction, type
|
|
2014
|
+
export { AbstractPool, AbstractWorker, CircularArray, type ClusterPoolOptions, ClusterWorker, Deque, DynamicClusterPool, DynamicThreadPool, type ErrorHandler, type EventLoopUtilizationMeasurementStatistics, type ExitHandler, FixedClusterPool, FixedThreadPool, type IPool, type IWorker, type IWorkerChoiceStrategy, type IWorkerNode, type KillBehavior, KillBehaviors, type KillHandler, type Measurement, type MeasurementOptions, type MeasurementStatistics, type MeasurementStatisticsRequirements, Measurements, type MessageHandler, type MessageValue, Node, type OnlineHandler, PoolEmitter, type PoolEvent, PoolEvents, type PoolInfo, type PoolOptions, type PoolType, PoolTypes, type PromiseResponseWrapper, type StrategyData, type StrategyPolicy, type Task, type TaskAsyncFunction, type TaskFunction, type TaskFunctionOperationResult, type TaskFunctions, type TaskPerformance, type TaskStatistics, type TaskStatisticsRequirements, type TaskSyncFunction, type TasksQueueOptions, type ThreadPoolOptions, ThreadWorker, WorkerChoiceStrategies, type WorkerChoiceStrategy, WorkerChoiceStrategyContext, type WorkerChoiceStrategyOptions, type WorkerError, type WorkerInfo, type WorkerNodeEventCallback, type WorkerOptions, type WorkerStatistics, type WorkerType, WorkerTypes, type WorkerUsage, type Writable, availableParallelism };
|
package/lib/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("node:events"),t=require("node:worker_threads"),s=require("node:cluster"),r=require("node:crypto"),i=require("node:perf_hooks"),o=require("node:fs"),a=require("node:os"),n=require("node:async_hooks");function u(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(s){if("default"!==s){var r=Object.getOwnPropertyDescriptor(e,s);Object.defineProperty(t,s,r.get?r:{enumerable:!0,get:function(){return e[s]}})}})),t.default=e,Object.freeze(t)}var h=u(a);const k=Object.freeze({fixed:"fixed",dynamic:"dynamic"});class d extends e.EventEmitter{}const c=Object.freeze({ready:"ready",busy:"busy",full:"full",destroy:"destroy",error:"error",taskError:"taskError",backPressure:"backPressure"}),l=Object.freeze({thread:"thread",cluster:"cluster"}),g="default",m=Object.freeze((()=>{})),p={retries:6,runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},w={aggregate:!1,average:!1,median:!1},y=e=>e instanceof t.Worker?l.thread:e instanceof s.Worker?l.cluster:void 0,T=e=>e instanceof t.Worker?e.threadId:e instanceof s.Worker?e.id:void 0,f=e=>Array.isArray(e)&&0===e.length?0:Array.isArray(e)&&1===e.length?e[0]:e.reduce(((e,t)=>e+t),0)/e.length,W=e=>{if(Array.isArray(e)&&0===e.length)return 0;if(Array.isArray(e)&&1===e.length)return e[0];const t=e.slice().sort(((e,t)=>e-t));return(t[t.length-1>>1]+t[t.length>>1])/2},N=(e,t=2)=>{const s=Math.pow(10,t);return Math.round(e*s*(1+Number.EPSILON))/s},S=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),x=(e,t)=>t===e,E=e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name,v=(e,t,s)=>{t.aggregate&&(e.aggregate=(e.aggregate??0)+s,e.minimum=C(s,e.minimum??1/0),e.maximum=b(s,e.maximum??-1/0),(t.average||t.median)&&null!=s&&(e.history.push(s),t.average?e.average=f(e.history):null!=e.average&&delete e.average,t.median?e.median=W(e.history):null!=e.median&&delete e.median))},I=()=>r.webcrypto.getRandomValues(new Uint32Array(1))[0]/4294967296,C=(...e)=>e.reduce(((e,t)=>e<t?e:t),1/0),b=(...e)=>e.reduce(((e,t)=>e>t?e:t),-1/0),R=Object.freeze({SOFT:"SOFT",HARD:"HARD"}),z=Object.freeze({ROUND_ROBIN:"ROUND_ROBIN",LEAST_USED:"LEAST_USED",LEAST_BUSY:"LEAST_BUSY",LEAST_ELU:"LEAST_ELU",FAIR_SHARE:"FAIR_SHARE",WEIGHTED_ROUND_ROBIN:"WEIGHTED_ROUND_ROBIN",INTERLEAVED_WEIGHTED_ROUND_ROBIN:"INTERLEAVED_WEIGHTED_ROUND_ROBIN"}),O=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"});class P{pool;opts;nextWorkerNodeKey=0;previousWorkerNodeKey=0;strategyPolicy={dynamicWorkerUsage:!1,dynamicWorkerReady:!0};taskStatisticsRequirements={runTime:w,waitTime:w,elu:w};constructor(e,t=p){this.pool=e,this.opts=t,this.opts={...p,...t},this.choose=this.choose.bind(this)}setTaskStatisticsRequirements(e){this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.runTime,e.runTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.waitTime,e.waitTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.elu,e.elu?.median)}toggleMedianMeasurementStatisticsRequirements(e,t){e.average&&t&&(e.average=!1,e.median=t),e.median&&!t&&(e.average=!0,e.median=t)}resetWorkerNodeKeyProperties(){this.nextWorkerNodeKey=0,this.previousWorkerNodeKey=0}setOptions(e){this.opts={...p,...e},this.setTaskStatisticsRequirements(this.opts)}isWorkerNodeReady(e){return this.pool.workerNodes[e].info.ready}hasWorkerNodeBackPressure(e){return this.pool.hasWorkerNodeBackPressure(e)}isWorkerNodeEligible(e){return this.isWorkerNodeReady(e)&&!this.hasWorkerNodeBackPressure(e)}getWorkerNodeTaskRunTime(e){return this.taskStatisticsRequirements.runTime.median?this.pool.workerNodes[e].usage.runTime.median??0:this.pool.workerNodes[e].usage.runTime.average??0}getWorkerNodeTaskWaitTime(e){return this.taskStatisticsRequirements.waitTime.median?this.pool.workerNodes[e].usage.waitTime.median??0:this.pool.workerNodes[e].usage.waitTime.average??0}getWorkerNodeTaskElu(e){return this.taskStatisticsRequirements.elu.median?this.pool.workerNodes[e].usage.elu.active.median??0:this.pool.workerNodes[e].usage.elu.active.average??0}setPreviousWorkerNodeKey(e){this.previousWorkerNodeKey=e??this.previousWorkerNodeKey}checkNextWorkerNodeEligibility(){this.isWorkerNodeEligible(this.nextWorkerNodeKey)||(this.nextWorkerNodeKey=void 0)}computeDefaultWorkerWeight(){let e=0;for(const t of a.cpus()){const s=t.speed.toString().length-1;e+=1/(t.speed/Math.pow(10,s))*Math.pow(10,s)}return Math.round(e/a.cpus().length)}}class Q extends P{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:w,elu:{aggregate:!0,average:!0,median:!1}};constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){for(const e of this.pool.workerNodes)delete e.strategyData?.virtualTaskEndTimestamp;return!0}update(e){return this.pool.workerNodes[e].strategyData={virtualTaskEndTimestamp:this.computeWorkerNodeVirtualTaskEndTimestamp(e)},!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.fairShareNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}fairShareNextWorkerNodeKey(){return this.pool.workerNodes.reduce(((e,t,s,r)=>(null==t.strategyData?.virtualTaskEndTimestamp&&(t.strategyData={virtualTaskEndTimestamp:this.computeWorkerNodeVirtualTaskEndTimestamp(s)}),t.strategyData.virtualTaskEndTimestamp<r[e].strategyData.virtualTaskEndTimestamp?s:e)),0)}computeWorkerNodeVirtualTaskEndTimestamp(e){return this.getWorkerNodeVirtualTaskEndTimestamp(e,this.getWorkerNodeVirtualTaskStartTimestamp(e))}getWorkerNodeVirtualTaskEndTimestamp(e,t){return t+(this.opts.measurement===O.elu?this.getWorkerNodeTaskElu(e):this.getWorkerNodeTaskRunTime(e))}getWorkerNodeVirtualTaskStartTimestamp(e){const t=this.pool.workerNodes[e]?.strategyData?.virtualTaskEndTimestamp,s=performance.now();return s<(t??-1/0)?t:s}}class F extends P{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:w,elu:w};roundId=0;defaultWorkerWeight;roundWeights;workerNodeId=0;workerNodeVirtualTaskRunTime=0;constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight(),this.roundWeights=this.getRoundWeights()}reset(){return this.resetWorkerNodeKeyProperties(),this.roundId=0,this.workerNodeId=0,this.workerNodeVirtualTaskRunTime=0,!0}update(){return!0}choose(){for(let e=this.roundId;e<this.roundWeights.length;e++){this.roundId=e;for(let t=this.workerNodeId;t<this.pool.workerNodes.length;t++){this.workerNodeId=t,this.workerNodeId!==this.nextWorkerNodeKey&&0!==this.workerNodeVirtualTaskRunTime&&(this.workerNodeVirtualTaskRunTime=0);const s=this.opts.weights?.[t]??this.defaultWorkerWeight;if(s>=this.roundWeights[e]&&this.workerNodeVirtualTaskRunTime<s)return this.workerNodeVirtualTaskRunTime=this.workerNodeVirtualTaskRunTime+this.getWorkerNodeTaskRunTime(t),this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=t,this.nextWorkerNodeKey}}this.interleavedWeightedRoundRobinNextWorkerNodeId()}interleavedWeightedRoundRobinNextWorkerNodeId(){this.roundId===this.roundWeights.length-1&&this.workerNodeId===this.pool.workerNodes.length-1?(this.roundId=0,this.workerNodeId=0):this.workerNodeId===this.pool.workerNodes.length-1?(this.roundId=this.roundId+1,this.workerNodeId=0):this.workerNodeId=this.workerNodeId+1}remove(e){return 0===this.pool.workerNodes.length&&this.reset(),this.workerNodeId===e&&this.workerNodeId>this.pool.workerNodes.length-1&&(this.workerNodeId=this.pool.workerNodes.length-1),this.previousWorkerNodeKey===e&&this.previousWorkerNodeKey>this.pool.workerNodes.length-1&&(this.previousWorkerNodeKey=this.pool.workerNodes.length-1),!0}setOptions(e){super.setOptions(e),this.roundWeights=this.getRoundWeights()}getRoundWeights(){return null==this.opts.weights?[this.defaultWorkerWeight]:[...new Set(Object.values(this.opts.weights).slice().sort(((e,t)=>e-t)))]}}class K extends P{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:w};constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastBusyNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastBusyNextWorkerNodeKey(){return this.pool.workerNodes.reduce(((e,t,s,r)=>(t.usage.runTime.aggregate??0)+(t.usage.waitTime.aggregate??0)<(r[e].usage.runTime.aggregate??0)+(r[e].usage.waitTime.aggregate??0)?s:e),0)}}class M extends P{constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastUsedNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastUsedNextWorkerNodeKey(){return this.pool.workerNodes.reduce(((e,t,s,r)=>t.usage.tasks.executed+t.usage.tasks.executing+t.usage.tasks.queued<r[e].usage.tasks.executed+r[e].usage.tasks.executing+r[e].usage.tasks.queued?s:e),0)}}class q extends P{taskStatisticsRequirements={runTime:w,waitTime:w,elu:{aggregate:!0,average:!1,median:!1}};constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastEluNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastEluNextWorkerNodeKey(){return this.pool.workerNodes.reduce(((e,t,s,r)=>(t.usage.elu.active.aggregate??0)<(r[e].usage.elu.active.aggregate??0)?s:e),0)}}class A extends P{constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.resetWorkerNodeKeyProperties(),!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;return this.setPreviousWorkerNodeKey(e),this.roundRobinNextWorkerNodeKey(),e}remove(e){return 0===this.pool.workerNodes.length&&this.reset(),this.nextWorkerNodeKey===e&&this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1),this.previousWorkerNodeKey===e&&this.previousWorkerNodeKey>this.pool.workerNodes.length-1&&(this.previousWorkerNodeKey=this.pool.workerNodes.length-1),!0}roundRobinNextWorkerNodeKey(){return this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,this.nextWorkerNodeKey}}class U extends P{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:w,elu:w};defaultWorkerWeight;workerNodeVirtualTaskRunTime=0;constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight()}reset(){return this.resetWorkerNodeKeyProperties(),this.workerNodeVirtualTaskRunTime=0,!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.weightedRoundRobinNextWorkerNodeKey()}remove(e){return 0===this.pool.workerNodes.length&&this.reset(),this.nextWorkerNodeKey===e&&(this.workerNodeVirtualTaskRunTime=0,this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1)),this.previousWorkerNodeKey===e&&this.previousWorkerNodeKey>this.pool.workerNodes.length-1&&(this.previousWorkerNodeKey=this.pool.workerNodes.length-1),!0}weightedRoundRobinNextWorkerNodeKey(){const e=this.opts.weights?.[this.nextWorkerNodeKey??this.previousWorkerNodeKey]??this.defaultWorkerWeight;return this.workerNodeVirtualTaskRunTime<e?this.workerNodeVirtualTaskRunTime=this.workerNodeVirtualTaskRunTime+this.getWorkerNodeTaskRunTime(this.nextWorkerNodeKey??this.previousWorkerNodeKey):(this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,this.workerNodeVirtualTaskRunTime=0),this.nextWorkerNodeKey}}class B{workerChoiceStrategy;opts;workerChoiceStrategies;retriesCount=0;constructor(e,t=z.ROUND_ROBIN,s=p){this.workerChoiceStrategy=t,this.opts=s,this.opts={...p,...s},this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[z.ROUND_ROBIN,new(A.bind(this))(e,s)],[z.LEAST_USED,new(M.bind(this))(e,s)],[z.LEAST_BUSY,new(K.bind(this))(e,s)],[z.LEAST_ELU,new(q.bind(this))(e,s)],[z.FAIR_SHARE,new(Q.bind(this))(e,s)],[z.WEIGHTED_ROUND_ROBIN,new(U.bind(this))(e,s)],[z.INTERLEAVED_WEIGHTED_ROUND_ROBIN,new(F.bind(this))(e,s)]])}getStrategyPolicy(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).strategyPolicy}getTaskStatisticsRequirements(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).taskStatisticsRequirements}setWorkerChoiceStrategy(e){this.workerChoiceStrategy!==e&&(this.workerChoiceStrategy=e),this.workerChoiceStrategies.get(this.workerChoiceStrategy)?.reset()}update(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).update(e)}execute(){const e=this.workerChoiceStrategies.get(this.workerChoiceStrategy).choose();if(null==e&&this.retriesCount<this.opts.retries)return this.retriesCount++,this.execute();if(null==e)throw new Error(`Worker node key chosen is null or undefined after ${this.retriesCount} retries`);return this.retriesCount=0,e}remove(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).remove(e)}setOptions(e){this.opts={...p,...e};for(const t of this.workerChoiceStrategies.values())t.setOptions(e)}}class D extends Array{size;constructor(e=1024,...t){super(),this.checkSize(e),this.size=e,arguments.length>1&&this.push(...t)}push(...e){const t=super.push(...e);return t>this.size&&super.splice(0,t-this.size),this.length}unshift(...e){return super.unshift(...e)>this.size&&super.splice(this.size,e.length),this.length}concat(...e){const t=super.concat(e);return t.size=this.size,t.length>t.size&&t.splice(0,t.length-t.size),t}splice(e,t,...s){let r=[];if(arguments.length>=3&&null!=t){if(r=super.splice(e,t,...s),this.length>this.size){const e=super.splice(0,this.length-this.size);r=new D(r.length+e.length,...r,...e)}}else r=2===arguments.length?super.splice(e,t):super.splice(e);return r}resize(e){if(this.checkSize(e),0===e)this.length=0;else if(e<this.size)for(let t=e;t<this.size;t++)super.pop();this.size=e}empty(){return 0===this.length}full(){return this.length===this.size}checkSize(e){if(!Number.isSafeInteger(e))throw new TypeError(`Invalid circular array size: ${e} is not a safe integer`);if(e<0)throw new RangeError(`Invalid circular array size: ${e} < 0`)}}class L{data;next;prev;constructor(e){this.data=e}}class V{head;tail;size;maxSize;constructor(){this.clear()}push(e){const t=new L(e);return null==this.tail?this.head=this.tail=t:(t.prev=this.tail,this.tail=this.tail.next=t),this.incrementSize()}unshift(e){const t=new L(e);return null==this.head?this.head=this.tail=t:(t.next=this.head,this.head=this.head.prev=t),this.incrementSize()}pop(){if(null==this.head)return;const e=this.tail;return this.tail=this.tail.prev,null==this.tail?this.head=void 0:this.tail.next=void 0,--this.size,e?.data}shift(){if(null==this.head)return;const e=this.head;return this.head=this.head.next,null==this.head?this.tail=void 0:this.head.prev=void 0,--this.size,e?.data}peekFirst(){return this.head?.data}peekLast(){return this.tail?.data}clear(){this.head=void 0,this.tail=void 0,this.size=0,this.maxSize=0}[Symbol.iterator](){let e=this.head;return{next:()=>{if(null==e)return{value:void 0,done:!0};const t={value:e.data,done:!1};return e=e.next,t}}}backward(){return{[Symbol.iterator]:()=>{let e=this.tail;return{next:()=>{if(null==e)return{value:void 0,done:!0};const t={value:e.data,done:!1};return e=e.prev,t}}}}}incrementSize(){return++this.size,this.size>this.maxSize&&(this.maxSize=this.size),this.size}}class _{worker;info;usage;strategyData;messageChannel;tasksQueueBackPressureSize;onBackPressure;onEmptyQueue;tasksQueue;onBackPressureStarted;onEmptyQueueCount;taskFunctionsUsage;constructor(e,s){this.checkWorkerNodeArguments(e,s),this.worker=e,this.info=this.initWorkerInfo(e),this.usage=this.initWorkerUsage(),this.info.type===l.thread&&(this.messageChannel=new t.MessageChannel),this.tasksQueueBackPressureSize=s,this.tasksQueue=new V,this.onBackPressureStarted=!1,this.onEmptyQueueCount=0,this.taskFunctionsUsage=new Map}tasksQueueSize(){return this.tasksQueue.size}enqueueTask(e){const t=this.tasksQueue.push(e);return null!=this.onBackPressure&&this.hasBackPressure()&&!this.onBackPressureStarted&&(this.onBackPressureStarted=!0,this.onBackPressure(this.info.id),this.onBackPressureStarted=!1),t}unshiftTask(e){const t=this.tasksQueue.unshift(e);return null!=this.onBackPressure&&this.hasBackPressure()&&!this.onBackPressureStarted&&(this.onBackPressureStarted=!0,this.onBackPressure(this.info.id),this.onBackPressureStarted=!1),t}dequeueTask(){const e=this.tasksQueue.shift();return null!=this.onEmptyQueue&&0===this.tasksQueue.size&&0===this.onEmptyQueueCount&&this.startOnEmptyQueue().catch(m),e}popTask(){const e=this.tasksQueue.pop();return null!=this.onEmptyQueue&&0===this.tasksQueue.size&&0===this.onEmptyQueueCount&&this.startOnEmptyQueue().catch(m),e}clearTasksQueue(){this.tasksQueue.clear()}hasBackPressure(){return this.tasksQueue.size>=this.tasksQueueBackPressureSize}resetUsage(){this.usage=this.initWorkerUsage(),this.taskFunctionsUsage.clear()}closeChannel(){null!=this.messageChannel&&(this.messageChannel?.port1.unref(),this.messageChannel?.port2.unref(),this.messageChannel?.port1.close(),this.messageChannel?.port2.close(),delete this.messageChannel)}getTaskFunctionWorkerUsage(e){if(!Array.isArray(this.info.taskFunctions))throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function names list is not yet defined`);if(Array.isArray(this.info.taskFunctions)&&this.info.taskFunctions.length<3)throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function names list has less than 3 elements`);return e===g&&(e=this.info.taskFunctions[1]),this.taskFunctionsUsage.has(e)||this.taskFunctionsUsage.set(e,this.initTaskFunctionWorkerUsage(e)),this.taskFunctionsUsage.get(e)}async startOnEmptyQueue(){this.onEmptyQueueCount>0&&(this.usage.tasks.executing>0||this.tasksQueue.size>0)?this.onEmptyQueueCount=0:(++this.onEmptyQueueCount,this.onEmptyQueue?.(this.info.id),await(async e=>{await new Promise((t=>{setTimeout(t,e)}))})(((e=0,t=100)=>{const s=Math.pow(2,e)*t;return s+.2*s*I()})(this.onEmptyQueueCount)),await this.startOnEmptyQueue())}initWorkerInfo(e){return{id:T(e),type:y(e),dynamic:!1,ready:!1}}initWorkerUsage(){const e=()=>this.tasksQueue.size,t=()=>this.tasksQueue.maxSize;return{tasks:{executed:0,executing:0,get queued(){return e()},get maxQueued(){return t()},stolen:0,failed:0},runTime:{history:new D},waitTime:{history:new D},elu:{idle:{history:new D},active:{history:new D}}}}initTaskFunctionWorkerUsage(e){const t=()=>{let t=0;for(const s of this.tasksQueue)(s.name===g&&e===this.info.taskFunctions[1]||s.name!==g&&e===s.name)&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},stolen:0,failed:0},runTime:{history:new D},waitTime:{history:new D},elu:{idle:{history:new D},active:{history:new D}}}}checkWorkerNodeArguments(e,t){if(null==e)throw new TypeError("Cannot construct a worker node without a worker");if(null==t)throw new TypeError("Cannot construct a worker node without a tasks queue back pressure size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot construct a worker node with a tasks queue back pressure size that is not an integer");if(t<=0)throw new RangeError("Cannot construct a worker node with a tasks queue back pressure size that is not a positive integer")}}class j{numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;max;started;starting;startTimestamp;constructor(e,t,s){if(this.numberOfWorkers=e,this.filePath=t,this.opts=s,!this.isMain())throw new Error("Cannot start a pool from a worker with the same type as the pool");this.checkNumberOfWorkers(this.numberOfWorkers),this.checkFilePath(this.filePath),this.checkPoolOptions(this.opts),this.chooseWorkerNode=this.chooseWorkerNode.bind(this),this.executeTask=this.executeTask.bind(this),this.enqueueTask=this.enqueueTask.bind(this),!0===this.opts.enableEvents&&(this.emitter=new d),this.workerChoiceStrategyContext=new B(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook(),this.started=!1,this.starting=!1,!0===this.opts.startWorkers&&this.start(),this.startTimestamp=i.performance.now()}checkFilePath(e){if(null==e||"string"!=typeof e||"string"==typeof e&&0===e.trim().length)throw new Error("Please specify a file with a worker implementation");if(!o.existsSync(e))throw new Error(`Cannot find the worker file '${e}'`)}checkNumberOfWorkers(e){if(null==e)throw new Error("Cannot instantiate a pool without specifying the number of workers");if(!Number.isSafeInteger(e))throw new TypeError("Cannot instantiate a pool with a non safe integer number of workers");if(e<0)throw new RangeError("Cannot instantiate a pool with a negative number of workers");if(this.type===k.fixed&&0===e)throw new RangeError("Cannot instantiate a fixed pool with zero worker")}checkDynamicPoolSize(e,t){if(this.type===k.dynamic){if(null==t)throw new TypeError("Cannot instantiate a dynamic pool without specifying the maximum pool size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot instantiate a dynamic pool with a non safe integer maximum pool size");if(e>t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size");if(0===t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size equal to zero");if(e===t)throw new RangeError("Cannot instantiate a dynamic pool with a minimum pool size equal to the maximum pool size. Use a fixed pool instead")}}checkPoolOptions(e){if(!S(e))throw new TypeError("Invalid pool options: must be a plain object");this.opts.startWorkers=e.startWorkers??!0,this.opts.workerChoiceStrategy=e.workerChoiceStrategy??z.ROUND_ROBIN,this.checkValidWorkerChoiceStrategy(this.opts.workerChoiceStrategy),this.opts.workerChoiceStrategyOptions={...p,...e.workerChoiceStrategyOptions},this.checkValidWorkerChoiceStrategyOptions(this.opts.workerChoiceStrategyOptions),this.opts.restartWorkerOnError=e.restartWorkerOnError??!0,this.opts.enableEvents=e.enableEvents??!0,this.opts.enableTasksQueue=e.enableTasksQueue??!1,this.opts.enableTasksQueue&&(this.checkValidTasksQueueOptions(e.tasksQueueOptions),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e.tasksQueueOptions))}checkValidWorkerChoiceStrategy(e){if(!Object.values(z).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)}checkValidWorkerChoiceStrategyOptions(e){if(!S(e))throw new TypeError("Invalid worker choice strategy options: must be a plain object");if(null!=e.retries&&!Number.isSafeInteger(e.retries))throw new TypeError("Invalid worker choice strategy options: retries must be an integer");if(null!=e.retries&&e.retries<0)throw new RangeError(`Invalid worker choice strategy options: retries '${e.retries}' must be greater or equal than zero`);if(null!=e.weights&&Object.keys(e.weights).length!==this.maxSize)throw new Error("Invalid worker choice strategy options: must have a weight for each worker node");if(null!=e.measurement&&!Object.values(O).includes(e.measurement))throw new Error(`Invalid worker choice strategy options: invalid measurement '${e.measurement}'`)}checkValidTasksQueueOptions(e){if(null!=e&&!S(e))throw new TypeError("Invalid tasks queue options: must be a plain object");if(null!=e?.concurrency&&!Number.isSafeInteger(e?.concurrency))throw new TypeError("Invalid worker node tasks concurrency: must be an integer");if(null!=e?.concurrency&&e?.concurrency<=0)throw new RangeError(`Invalid worker node tasks concurrency: ${e?.concurrency} is a negative integer or zero`);if(null!=e?.size&&!Number.isSafeInteger(e?.size))throw new TypeError("Invalid worker node tasks queue size: must be an integer");if(null!=e?.size&&e?.size<=0)throw new RangeError(`Invalid worker node tasks queue size: ${e?.size} is a negative integer or zero`)}get info(){return{version:"2.6.45",type:this.type,worker:this.worker,started:this.started,ready:this.ready,strategy:this.opts.workerChoiceStrategy,minSize:this.minSize,maxSize:this.maxSize,...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{utilization:N(this.utilization)},workerNodes:this.workerNodes.length,idleWorkerNodes:this.workerNodes.reduce(((e,t)=>0===t.usage.tasks.executing?e+1:e),0),busyWorkerNodes:this.workerNodes.reduce(((e,t)=>t.usage.tasks.executing>0?e+1:e),0),executedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executed),0),executingTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executing),0),...!0===this.opts.enableTasksQueue&&{queuedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.queued),0)},...!0===this.opts.enableTasksQueue&&{maxQueuedTasks:this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.maxQueued??0)),0)},...!0===this.opts.enableTasksQueue&&{backPressure:this.hasBackPressure()},...!0===this.opts.enableTasksQueue&&{stolenTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.stolen),0)},failedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.failed),0),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&{runTime:{minimum:N(C(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:N(b(...this.workerNodes.map((e=>e.usage.runTime?.maximum??-1/0)))),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.average&&{average:N(f(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&{median:N(W(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:N(C(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:N(b(...this.workerNodes.map((e=>e.usage.waitTime?.maximum??-1/0)))),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.average&&{average:N(f(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.waitTime.history)),[])))},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&{median:N(W(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.waitTime.history)),[])))}}}}}get ready(){return this.workerNodes.reduce(((e,t)=>!t.info.dynamic&&t.info.ready?e+1:e),0)>=this.minSize}get utilization(){const e=(i.performance.now()-this.startTimestamp)*this.maxSize;return(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)+this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0))/e}get minSize(){return this.numberOfWorkers}get maxSize(){return this.max??this.numberOfWorkers}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Worker message received without worker id");if(null!=e.workerId&&-1===this.getWorkerNodeKeyByWorkerId(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKeyByWorker(e){return this.workerNodes.findIndex((t=>t.worker===e))}getWorkerNodeKeyByWorkerId(e){return this.workerNodes.findIndex((t=>t.info.id===e))}setWorkerChoiceStrategy(e,t){this.checkValidWorkerChoiceStrategy(e),this.opts.workerChoiceStrategy=e,this.workerChoiceStrategyContext.setWorkerChoiceStrategy(this.opts.workerChoiceStrategy),null!=t&&this.setWorkerChoiceStrategyOptions(t);for(const[e,t]of this.workerNodes.entries())t.resetUsage(),this.sendStatisticsMessageToWorker(e)}setWorkerChoiceStrategyOptions(e){this.checkValidWorkerChoiceStrategyOptions(e),this.opts.workerChoiceStrategyOptions={...p,...e},this.workerChoiceStrategyContext.setOptions(this.opts.workerChoiceStrategyOptions)}enableTasksQueue(e,t){!0!==this.opts.enableTasksQueue||e||this.flushTasksQueues(),this.opts.enableTasksQueue=e,this.setTasksQueueOptions(t)}setTasksQueueOptions(e){!0===this.opts.enableTasksQueue?(this.checkValidTasksQueueOptions(e),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e),this.setTasksQueueSize(this.opts.tasksQueueOptions.size)):null!=this.opts.tasksQueueOptions&&delete this.opts.tasksQueueOptions}setTasksQueueSize(e){for(const t of this.workerNodes)t.tasksQueueBackPressureSize=e}buildTasksQueueOptions(e){return{size:Math.pow(this.maxSize,2),concurrency:1,taskStealing:!0,tasksStealingOnBackPressure:!0,...e}}get full(){return this.workerNodes.length>=this.maxSize}internalBusy(){return!0===this.opts.enableTasksQueue?-1===this.workerNodes.findIndex((e=>e.info.ready&&e.usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency)):-1===this.workerNodes.findIndex((e=>e.info.ready&&0===e.usage.tasks.executing))}listTaskFunctions(){for(const e of this.workerNodes)if(Array.isArray(e.info.taskFunctions)&&e.info.taskFunctions.length>0)return e.info.taskFunctions;return[]}shallExecuteTask(e){return 0===this.tasksQueueSize(e)&&this.workerNodes[e].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency}async execute(e,t,s){return await new Promise(((o,a)=>{if(!this.started)return void a(new Error("Cannot execute a task on not started pool"));if(null!=t&&"string"!=typeof t)return void a(new TypeError("name argument must be a string"));if(null!=t&&"string"==typeof t&&0===t.trim().length)return void a(new TypeError("name argument must not be an empty string"));if(null!=s&&!Array.isArray(s))return void a(new TypeError("transferList argument must be an array"));const n=i.performance.now(),u=this.chooseWorkerNode(),h={name:t??g,data:e??{},transferList:s,timestamp:n,workerId:this.getWorkerInfo(u).id,taskId:r.randomUUID()};this.promiseResponseMap.set(h.taskId,{resolve:o,reject:a,workerNodeKey:u}),!1===this.opts.enableTasksQueue||!0===this.opts.enableTasksQueue&&this.shallExecuteTask(u)?this.executeTask(u,h):this.enqueueTask(u,h)}))}start(){for(this.starting=!0;this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.numberOfWorkers;)this.createAndSetupWorkerNode();this.starting=!1,this.started=!0}async destroy(){await Promise.all(this.workerNodes.map((async(e,t)=>{await this.destroyWorkerNode(t)}))),this.emitter?.emit(c.destroy,this.info),this.started=!1}async sendKillMessageToWorker(e,t){await new Promise(((s,r)=>{this.registerWorkerMessageListener(e,(e=>{"success"===e.kill?s():"failure"===e.kill&&r(new Error(`Worker ${t} kill message handling failed`))})),this.sendToWorker(e,{kill:!0,workerId:t})}))}setupHook(){}beforeTaskExecutionHook(e,t){if(null!=this.workerNodes[e]?.usage){const s=this.workerNodes[e].usage;++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t)}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name)){const s=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name);++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t)}}afterTaskExecutionHook(e,t){if(null!=this.workerNodes[e]?.usage){const s=this.workerNodes[e].usage;this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t)}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance?.name)){const s=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance?.name);this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t)}}shallUpdateTaskFunctionWorkerUsage(e){const t=this.getWorkerInfo(e);return null!=t&&Array.isArray(t.taskFunctions)&&t.taskFunctions.length>2}updateTaskStatisticsWorkerUsage(e,t){const s=e.tasks;null!=s.executing&&s.executing>0&&--s.executing,null==t.taskError?++s.executed:++s.failed}updateRunTimeWorkerUsage(e,t){null==t.taskError&&v(e.runTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime,t.taskPerformance?.runTime??0)}updateWaitTimeWorkerUsage(e,t){const s=i.performance.now(),r=s-(t.timestamp??s);v(e.waitTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime,r)}updateEluWorkerUsage(e,t){if(null!=t.taskError)return;const s=this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu;v(e.elu.active,s,t.taskPerformance?.elu?.active??0),v(e.elu.idle,s,t.taskPerformance?.elu?.idle??0),s.aggregate&&null!=t.taskPerformance?.elu&&(null!=e.elu.utilization?e.elu.utilization=(e.elu.utilization+t.taskPerformance.elu.utilization)/2:e.elu.utilization=t.taskPerformance.elu.utilization)}chooseWorkerNode(){if(this.shallCreateDynamicWorker()){const e=this.createAndSetupDynamicWorkerNode();if(this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerUsage)return e}return this.workerChoiceStrategyContext.execute()}shallCreateDynamicWorker(){return this.type===k.dynamic&&!this.full&&this.internalBusy()}createAndSetupWorkerNode(){const e=this.createWorker();e.on("online",this.opts.onlineHandler??m),e.on("message",this.opts.messageHandler??m),e.on("error",this.opts.errorHandler??m),e.on("error",(t=>{const s=this.getWorkerNodeKeyByWorker(e),r=this.getWorkerInfo(s);r.ready=!1,this.workerNodes[s].closeChannel(),this.emitter?.emit(c.error,t),!0===this.opts.restartWorkerOnError&&this.started&&!this.starting&&(r.dynamic?this.createAndSetupDynamicWorkerNode():this.createAndSetupWorkerNode()),!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(s)})),e.on("exit",this.opts.exitHandler??m),e.once("exit",(()=>{this.removeWorkerNode(e)}));const t=this.addWorkerNode(e);return this.afterWorkerNodeSetup(t),t}createAndSetupDynamicWorkerNode(){const e=this.createAndSetupWorkerNode();this.registerWorkerMessageListener(e,(e=>{const t=this.getWorkerNodeKeyByWorkerId(e.workerId),s=this.workerNodes[t].usage;(x(R.HARD,e.kill)||x(R.SOFT,e.kill)&&(!1===this.opts.enableTasksQueue&&0===s.tasks.executing||!0===this.opts.enableTasksQueue&&0===s.tasks.executing&&0===this.tasksQueueSize(t)))&&this.destroyWorkerNode(t).catch((e=>{this.emitter?.emit(c.error,e)}))}));const t=this.getWorkerInfo(e);return this.sendToWorker(e,{checkActive:!0,workerId:t.id}),t.dynamic=!0,(this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerReady||this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerUsage)&&(t.ready=!0),this.checkAndEmitDynamicWorkerCreationEvents(),e}afterWorkerNodeSetup(e){this.registerWorkerMessageListener(e,this.workerListener()),this.sendStartupMessageToWorker(e),this.sendStatisticsMessageToWorker(e),!0===this.opts.enableTasksQueue&&(!0===this.opts.tasksQueueOptions?.taskStealing&&(this.workerNodes[e].onEmptyQueue=this.taskStealingOnEmptyQueue.bind(this)),!0===this.opts.tasksQueueOptions?.tasksStealingOnBackPressure&&(this.workerNodes[e].onBackPressure=this.tasksStealingOnBackPressure.bind(this)))}sendStatisticsMessageToWorker(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate},workerId:this.getWorkerInfo(e).id})}redistributeQueuedTasks(e){for(;this.tasksQueueSize(e)>0;){const t=this.workerNodes.reduce(((e,t,s,r)=>t.info.ready&&t.usage.tasks.queued<r[e].usage.tasks.queued?s:e),0),s=this.workerNodes[t],r={...this.dequeueTask(e),workerId:s.info.id};this.shallExecuteTask(t)?this.executeTask(t,r):this.enqueueTask(t,r)}}updateTaskStolenStatisticsWorkerUsage(e,t){const s=this.workerNodes[e];if(null!=s?.usage&&++s.usage.tasks.stolen,this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=s.getTaskFunctionWorkerUsage(t)){++s.getTaskFunctionWorkerUsage(t).tasks.stolen}}taskStealingOnEmptyQueue(e){const t=this.getWorkerNodeKeyByWorkerId(e),s=this.workerNodes[t],r=this.workerNodes.slice().sort(((e,t)=>t.usage.tasks.queued-e.usage.tasks.queued)).find((t=>t.info.ready&&t.info.id!==e&&t.usage.tasks.queued>0));if(null!=r){const e={...r.popTask(),workerId:s.info.id};this.shallExecuteTask(t)?this.executeTask(t,e):this.enqueueTask(t,e),this.updateTaskStolenStatisticsWorkerUsage(t,e.name)}}tasksStealingOnBackPressure(e){if(this.opts.tasksQueueOptions?.size<=1)return;const t=this.workerNodes[this.getWorkerNodeKeyByWorkerId(e)],s=this.workerNodes.slice().sort(((e,t)=>e.usage.tasks.queued-t.usage.tasks.queued));for(const[r,i]of s.entries())if(t.usage.tasks.queued>0&&i.info.ready&&i.info.id!==e&&i.usage.tasks.queued<this.opts.tasksQueueOptions?.size-1){const e={...t.popTask(),workerId:i.info.id};this.shallExecuteTask(r)?this.executeTask(r,e):this.enqueueTask(r,e),this.updateTaskStolenStatisticsWorkerUsage(r,e.name)}}workerListener(){return e=>{this.checkMessageWorkerId(e),null!=e.ready&&null!=e.taskFunctions?this.handleWorkerReadyResponse(e):null!=e.taskId?this.handleTaskExecutionResponse(e):null!=e.taskFunctions&&(this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId)).taskFunctions=e.taskFunctions)}}handleWorkerReadyResponse(e){if(!1===e.ready)throw new Error(`Worker ${e.workerId} failed to initialize`);const t=this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId));t.ready=e.ready,t.taskFunctions=e.taskFunctions,null!=this.emitter&&this.ready&&this.emitter.emit(c.ready,this.info)}handleTaskExecutionResponse(e){const{taskId:t,taskError:s,data:r}=e,i=this.promiseResponseMap.get(t);if(null!=i){null!=s?(this.emitter?.emit(c.taskError,s),i.reject(s.message)):i.resolve(r);const o=i.workerNodeKey;this.afterTaskExecutionHook(o,e),this.workerChoiceStrategyContext.update(o),this.promiseResponseMap.delete(t),!0===this.opts.enableTasksQueue&&this.tasksQueueSize(o)>0&&this.workerNodes[o].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&this.executeTask(o,this.dequeueTask(o))}}checkAndEmitTaskExecutionEvents(){this.busy&&this.emitter?.emit(c.busy,this.info)}checkAndEmitTaskQueuingEvents(){this.hasBackPressure()&&this.emitter?.emit(c.backPressure,this.info)}checkAndEmitDynamicWorkerCreationEvents(){this.type===k.dynamic&&this.full&&this.emitter?.emit(c.full,this.info)}getWorkerInfo(e){return this.workerNodes[e].info}addWorkerNode(e){const t=new _(e,this.opts.tasksQueueOptions?.size??Math.pow(this.maxSize,2));this.starting&&(t.info.ready=!0),this.workerNodes.push(t);const s=this.getWorkerNodeKeyByWorker(e);if(-1===s)throw new Error("Worker added not found in worker nodes");return s}removeWorkerNode(e){const t=this.getWorkerNodeKeyByWorker(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategyContext.remove(t))}hasWorkerNodeBackPressure(e){return!0===this.opts.enableTasksQueue&&this.workerNodes[e].hasBackPressure()}hasBackPressure(){return!0===this.opts.enableTasksQueue&&-1===this.workerNodes.findIndex((e=>!e.hasBackPressure()))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(e,t,t.transferList),this.checkAndEmitTaskExecutionEvents()}enqueueTask(e,t){const s=this.workerNodes[e].enqueueTask(t);return this.checkAndEmitTaskQueuingEvents(),s}dequeueTask(e){return this.workerNodes[e].dequeueTask()}tasksQueueSize(e){return this.workerNodes[e].tasksQueueSize()}flushTasksQueue(e){for(;this.tasksQueueSize(e)>0;)this.executeTask(e,this.dequeueTask(e));this.workerNodes[e].clearTasksQueue()}flushTasksQueues(){for(const[e]of this.workerNodes.entries())this.flushTasksQueue(e)}}class H extends j{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}setupHook(){s.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return s.isPrimary}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e],s=t.worker,r=new Promise((e=>{s.on("exit",(()=>{e()}))}));s.on("disconnect",(()=>{s.kill()})),await this.sendKillMessageToWorker(e,t.info.id),s.disconnect(),await r}sendToWorker(e,t){this.workerNodes[e].worker.send(t)}sendStartupMessageToWorker(e){this.sendToWorker(e,{ready:!1,workerId:this.workerNodes[e].info.id})}registerWorkerMessageListener(e,t){this.workerNodes[e].worker.on("message",t)}createWorker(){return s.fork(this.opts.env)}get type(){return k.fixed}get worker(){return l.cluster}get busy(){return this.internalBusy()}}class $ extends j{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}isMain(){return t.isMainThread}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e],s=t.worker,r=new Promise((e=>{s.on("exit",(()=>{e()}))}));await this.sendKillMessageToWorker(e,t.info.id),t.closeChannel(),await s.terminate(),await r}sendToWorker(e,t,s){this.workerNodes[e].messageChannel.port1.postMessage(t,s)}sendStartupMessageToWorker(e){const t=this.workerNodes[e],s=t.worker,r=t.messageChannel.port2;s.postMessage({ready:!1,workerId:t.info.id,port:r},[r])}registerWorkerMessageListener(e,t){this.workerNodes[e].messageChannel.port1.on("message",t)}createWorker(){return new t.Worker(this.filePath,{env:t.SHARE_ENV,...this.opts.workerOptions})}get type(){return k.fixed}get worker(){return l.thread}get busy(){return this.internalBusy()}}const G=6e4,Y={killBehavior:R.SOFT,maxInactiveTime:G,killHandler:m};class J extends n.AsyncResource{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,s,r,i=Y){if(super(e),this.isMain=t,this.mainWorker=s,this.opts=i,null==this.isMain)throw new Error("isMain parameter is mandatory");this.checkTaskFunctions(r),this.checkWorkerOptions(this.opts),this.isMain||this.getMainWorker().on("message",this.handleReadyMessage.bind(this))}checkWorkerOptions(e){this.opts={...Y,...e},delete this.opts.async}checkValidTaskFunction(e,t){if("string"!=typeof e)throw new TypeError("A taskFunctions parameter object key is not a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("A taskFunctions parameter object key is an empty string");if("function"!=typeof t)throw new TypeError("A taskFunctions parameter object value is not a function")}checkTaskFunctions(e){if(null==e)throw new Error("taskFunctions parameter is mandatory");if(this.taskFunctions=new Map,"function"==typeof e){const t=e.bind(this);this.taskFunctions.set(g,t),this.taskFunctions.set("string"==typeof e.name&&e.name.trim().length>0?e.name:"fn1",t)}else{if(!S(e))throw new TypeError("taskFunctions parameter is not a function or a plain object");{let t=!0;for(const[s,r]of Object.entries(e)){this.checkValidTaskFunction(s,r);const e=r.bind(this);t&&(this.taskFunctions.set(g,e),t=!1),this.taskFunctions.set(s,e)}if(t)throw new Error("taskFunctions parameter object is empty")}}}hasTaskFunction(e){return this.checkTaskFunctionName(e),this.taskFunctions.has(e)}addTaskFunction(e,t){if(this.checkTaskFunctionName(e),e===g)throw new Error("Cannot add a task function with the default reserved name");if("function"!=typeof t)throw new TypeError("fn parameter is not a function");try{const s=t.bind(this);return this.taskFunctions.get(e)===this.taskFunctions.get(g)&&this.taskFunctions.set(g,s),this.taskFunctions.set(e,s),this.sendTaskFunctionsListToMainWorker(),!0}catch{return!1}}removeTaskFunction(e){if(this.checkTaskFunctionName(e),e===g)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(g))throw new Error("Cannot remove the task function used as the default task function");const t=this.taskFunctions.delete(e);return this.sendTaskFunctionsListToMainWorker(),t}listTaskFunctions(){const e=[...this.taskFunctions.keys()];let t=g;for(const[e,s]of this.taskFunctions)if(e!==g&&s===this.taskFunctions.get(g)){t=e;break}return[e[e.indexOf(g)],t,...e.filter((e=>e!==g&&e!==t))]}setDefaultTaskFunction(e){if(this.checkTaskFunctionName(e),e===g)throw new Error("Cannot set the default task function reserved name as the default task function");if(!this.taskFunctions.has(e))throw new Error("Cannot set the default task function to a non-existing task function");try{return this.taskFunctions.set(g,this.taskFunctions.get(e)),!0}catch{return!1}}checkTaskFunctionName(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("name parameter is an empty string")}messageListener(e){this.checkMessageWorkerId(e),null!=e.statistics?this.statistics=e.statistics:null!=e.checkActive?e.checkActive?this.startCheckActive():this.stopCheckActive():null!=e.taskId&&null!=e.data?this.run(e):!0===e.kill&&this.handleKillMessage(e)}handleKillMessage(e){if(this.stopCheckActive(),E(this.opts.killHandler))(this.opts.killHandler?.()).then((()=>(this.sendToMainWorker({kill:"success",workerId:this.id}),null))).catch((()=>{this.sendToMainWorker({kill:"failure",workerId:this.id})})).finally((()=>{this.emitDestroy()})).catch(m);else try{this.opts.killHandler?.(),this.sendToMainWorker({kill:"success",workerId:this.id})}catch{this.sendToMainWorker({kill:"failure",workerId:this.id})}finally{this.emitDestroy()}}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Message worker id is not set");if(null!=e.workerId&&e.workerId!==this.id)throw new Error(`Message worker id ${e.workerId} does not match the worker id ${this.id}`)}startCheckActive(){this.lastTaskTimestamp=i.performance.now(),this.activeInterval=setInterval(this.checkActive.bind(this),(this.opts.maxInactiveTime??G)/2)}stopCheckActive(){null!=this.activeInterval&&(clearInterval(this.activeInterval),delete this.activeInterval)}checkActive(){i.performance.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??G)&&this.sendToMainWorker({kill:this.opts.killBehavior,workerId:this.id})}getMainWorker(){if(null==this.mainWorker)throw new Error("Main worker not set");return this.mainWorker}sendTaskFunctionsListToMainWorker(){this.sendToMainWorker({taskFunctions:this.listTaskFunctions(),workerId:this.id})}handleError(e){return e instanceof Error?e.message:e}run(e){const{name:t,taskId:s,data:r}=e,i=this.taskFunctions.get(t??g);null!=i?E(i)?this.runInAsyncScope(this.runAsync.bind(this),this,i,e):this.runInAsyncScope(this.runSync.bind(this),this,i,e):this.sendToMainWorker({taskError:{name:t,message:`Task function '${t}' not found`,data:r},workerId:this.id,taskId:s})}runSync(e,t){const{name:s,taskId:r,data:i}=t;try{let t=this.beginTaskPerformance(s);const o=e(i);t=this.endTaskPerformance(t),this.sendToMainWorker({data:o,taskPerformance:t,workerId:this.id,taskId:r})}catch(e){this.sendToMainWorker({taskError:{name:s,message:this.handleError(e),data:i},workerId:this.id,taskId:r})}finally{this.updateLastTaskTimestamp()}}runAsync(e,t){const{name:s,taskId:r,data:i}=t;let o=this.beginTaskPerformance(s);e(i).then((e=>(o=this.endTaskPerformance(o),this.sendToMainWorker({data:e,taskPerformance:o,workerId:this.id,taskId:r}),null))).catch((e=>{this.sendToMainWorker({taskError:{name:s,message:this.handleError(e),data:i},workerId:this.id,taskId:r})})).finally((()=>{this.updateLastTaskTimestamp()})).catch(m)}beginTaskPerformance(e){return this.checkStatistics(),{name:e??g,timestamp:i.performance.now(),...this.statistics.elu&&{elu:i.performance.eventLoopUtilization()}}}endTaskPerformance(e){return this.checkStatistics(),{...e,...this.statistics.runTime&&{runTime:i.performance.now()-e.timestamp},...this.statistics.elu&&{elu:i.performance.eventLoopUtilization(e.elu)}}}checkStatistics(){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set")}updateLastTaskTimestamp(){null!=this.activeInterval&&(this.lastTaskTimestamp=i.performance.now())}}exports.ClusterWorker=class extends J{constructor(e,t={}){super("worker-cluster-pool:poolifier",s.isPrimary,s.worker,e,t)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready)try{this.getMainWorker().on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctions:this.listTaskFunctions(),workerId:this.id})}catch{this.sendToMainWorker({ready:!1,taskFunctions:this.listTaskFunctions(),workerId:this.id})}}get id(){return this.getMainWorker().id}sendToMainWorker(e){this.getMainWorker().send(e)}},exports.DynamicClusterPool=class extends H{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return k.dynamic}get busy(){return this.full&&this.internalBusy()}},exports.DynamicThreadPool=class extends ${max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return k.dynamic}get busy(){return this.full&&this.internalBusy()}},exports.FixedClusterPool=H,exports.FixedThreadPool=$,exports.KillBehaviors=R,exports.Measurements=O,exports.PoolEvents=c,exports.PoolTypes=k,exports.ThreadWorker=class extends J{port;constructor(e,s={}){super("worker-thread-pool:poolifier",t.isMainThread,t.parentPort,e,s)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready&&null!=e.port)try{this.port=e.port,this.port.on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctions:this.listTaskFunctions(),workerId:this.id})}catch{this.sendToMainWorker({ready:!1,taskFunctions:this.listTaskFunctions(),workerId:this.id})}}handleKillMessage(e){super.handleKillMessage(e),this.port?.unref(),this.port?.close()}get id(){return t.threadId}sendToMainWorker(e){this.port.postMessage(e)}handleError(e){return e}},exports.WorkerChoiceStrategies=z,exports.WorkerTypes=l,exports.availableParallelism=()=>{let e=1;try{e=h.availableParallelism()}catch{const t=h.cpus();Array.isArray(t)&&t.length>0&&(e=t.length)}return e};
|
|
1
|
+
"use strict";var e=require("node:events"),t=require("node:worker_threads"),s=require("node:fs"),r=require("node:os"),i=require("node:crypto"),o=require("node:cluster"),n=require("node:perf_hooks"),a=require("node:async_hooks");function u(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(s){if("default"!==s){var r=Object.getOwnPropertyDescriptor(e,s);Object.defineProperty(t,s,r.get?r:{enumerable:!0,get:function(){return e[s]}})}})),t.default=e,Object.freeze(t)}var h=u(r);const k=Object.freeze({fixed:"fixed",dynamic:"dynamic"});class c extends e.EventEmitter{}const d=Object.freeze({ready:"ready",busy:"busy",full:"full",destroy:"destroy",error:"error",taskError:"taskError",backPressure:"backPressure"}),l=Object.freeze({thread:"thread",cluster:"cluster"}),g="default",m=Object.freeze((()=>{})),p={retries:6,runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},w={aggregate:!1,average:!1,median:!1},y=e=>e instanceof t.Worker?l.thread:e instanceof o.Worker?l.cluster:void 0,T=e=>e instanceof t.Worker?e.threadId:e instanceof o.Worker?e.id:void 0,f=e=>Array.isArray(e)&&0===e.length?0:Array.isArray(e)&&1===e.length?e[0]:e.reduce(((e,t)=>e+t),0)/e.length,N=e=>{if(Array.isArray(e)&&0===e.length)return 0;if(Array.isArray(e)&&1===e.length)return e[0];const t=e.slice().sort(((e,t)=>e-t));return(t[t.length-1>>1]+t[t.length>>1])/2},W=(e,t=2)=>{const s=Math.pow(10,t);return Math.round(e*s*(1+Number.EPSILON))/s},S=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),x=(e,t)=>t===e,E=e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name,v=()=>i.webcrypto.getRandomValues(new Uint32Array(1))[0]/4294967296,b=(...e)=>e.reduce(((e,t)=>e<t?e:t),1/0),I=(...e)=>e.reduce(((e,t)=>e>t?e:t),-1/0),C=Object.freeze({ROUND_ROBIN:"ROUND_ROBIN",LEAST_USED:"LEAST_USED",LEAST_BUSY:"LEAST_BUSY",LEAST_ELU:"LEAST_ELU",FAIR_SHARE:"FAIR_SHARE",WEIGHTED_ROUND_ROBIN:"WEIGHTED_ROUND_ROBIN",INTERLEAVED_WEIGHTED_ROUND_ROBIN:"INTERLEAVED_WEIGHTED_ROUND_ROBIN"}),O=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"}),F=(e,t)=>{if(null==t)throw new TypeError("Cannot instantiate a dynamic pool without specifying the maximum pool size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot instantiate a dynamic pool with a non safe integer maximum pool size");if(e>t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size");if(0===t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size equal to zero");if(e===t)throw new RangeError("Cannot instantiate a dynamic pool with a minimum pool size equal to the maximum pool size. Use a fixed pool instead")},R=e=>{if(null!=e&&!Object.values(C).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)},z=e=>{if(null!=e&&!S(e))throw new TypeError("Invalid tasks queue options: must be a plain object");if(null!=e?.concurrency&&!Number.isSafeInteger(e.concurrency))throw new TypeError("Invalid worker node tasks concurrency: must be an integer");if(null!=e?.concurrency&&e.concurrency<=0)throw new RangeError(`Invalid worker node tasks concurrency: ${e.concurrency} is a negative integer or zero`);if(null!=e?.size&&!Number.isSafeInteger(e.size))throw new TypeError("Invalid worker node tasks queue size: must be an integer");if(null!=e?.size&&e.size<=0)throw new RangeError(`Invalid worker node tasks queue size: ${e.size} is a negative integer or zero`)},P=(e,t,s)=>{t.aggregate&&(e.aggregate=(e.aggregate??0)+s,e.minimum=b(s,e.minimum??1/0),e.maximum=I(s,e.maximum??-1/0),(t.average||t.median)&&null!=s&&(e.history.push(s),t.average?e.average=f(e.history):null!=e.average&&delete e.average,t.median?e.median=N(e.history):null!=e.median&&delete e.median))},M=Object.freeze({SOFT:"SOFT",HARD:"HARD"});class Q{pool;opts;nextWorkerNodeKey=0;previousWorkerNodeKey=0;strategyPolicy={dynamicWorkerUsage:!1,dynamicWorkerReady:!0};taskStatisticsRequirements={runTime:w,waitTime:w,elu:w};constructor(e,t=p){this.pool=e,this.opts=t,this.opts={...p,...t},this.choose=this.choose.bind(this)}setTaskStatisticsRequirements(e){this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.runTime,e.runTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.waitTime,e.waitTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.elu,e.elu?.median)}toggleMedianMeasurementStatisticsRequirements(e,t){e.average&&t&&(e.average=!1,e.median=t),e.median&&!t&&(e.average=!0,e.median=t)}resetWorkerNodeKeyProperties(){this.nextWorkerNodeKey=0,this.previousWorkerNodeKey=0}setOptions(e){this.opts={...p,...e},this.setTaskStatisticsRequirements(this.opts)}isWorkerNodeReady(e){return this.pool.workerNodes[e].info.ready}hasWorkerNodeBackPressure(e){return this.pool.hasWorkerNodeBackPressure(e)}isWorkerNodeEligible(e){return this.isWorkerNodeReady(e)&&!this.hasWorkerNodeBackPressure(e)}getWorkerNodeTaskRunTime(e){return this.taskStatisticsRequirements.runTime.median?this.pool.workerNodes[e].usage.runTime.median??0:this.pool.workerNodes[e].usage.runTime.average??0}getWorkerNodeTaskWaitTime(e){return this.taskStatisticsRequirements.waitTime.median?this.pool.workerNodes[e].usage.waitTime.median??0:this.pool.workerNodes[e].usage.waitTime.average??0}getWorkerNodeTaskElu(e){return this.taskStatisticsRequirements.elu.median?this.pool.workerNodes[e].usage.elu.active.median??0:this.pool.workerNodes[e].usage.elu.active.average??0}setPreviousWorkerNodeKey(e){this.previousWorkerNodeKey=e??this.previousWorkerNodeKey}checkNextWorkerNodeEligibility(){this.isWorkerNodeEligible(this.nextWorkerNodeKey)||(this.nextWorkerNodeKey=void 0)}computeDefaultWorkerWeight(){let e=0;for(const t of r.cpus()){const s=t.speed.toString().length-1;e+=1/(t.speed/Math.pow(10,s))*Math.pow(10,s)}return Math.round(e/r.cpus().length)}}class K extends Q{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:w,elu:{aggregate:!0,average:!0,median:!1}};constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){for(const e of this.pool.workerNodes)delete e.strategyData?.virtualTaskEndTimestamp;return!0}update(e){return this.pool.workerNodes[e].strategyData={virtualTaskEndTimestamp:this.computeWorkerNodeVirtualTaskEndTimestamp(e)},!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.fairShareNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}fairShareNextWorkerNodeKey(){return this.pool.workerNodes.reduce(((e,t,s,r)=>(null==t.strategyData?.virtualTaskEndTimestamp&&(t.strategyData={virtualTaskEndTimestamp:this.computeWorkerNodeVirtualTaskEndTimestamp(s)}),t.strategyData.virtualTaskEndTimestamp<r[e].strategyData.virtualTaskEndTimestamp?s:e)),0)}computeWorkerNodeVirtualTaskEndTimestamp(e){return this.getWorkerNodeVirtualTaskEndTimestamp(e,this.getWorkerNodeVirtualTaskStartTimestamp(e))}getWorkerNodeVirtualTaskEndTimestamp(e,t){return t+(this.opts.measurement===O.elu?this.getWorkerNodeTaskElu(e):this.getWorkerNodeTaskRunTime(e))}getWorkerNodeVirtualTaskStartTimestamp(e){const t=this.pool.workerNodes[e]?.strategyData?.virtualTaskEndTimestamp,s=performance.now();return s<(t??-1/0)?t:s}}class q extends Q{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:w,elu:w};roundId=0;defaultWorkerWeight;roundWeights;workerNodeId=0;workerNodeVirtualTaskRunTime=0;constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight(),this.roundWeights=this.getRoundWeights()}reset(){return this.resetWorkerNodeKeyProperties(),this.roundId=0,this.workerNodeId=0,this.workerNodeVirtualTaskRunTime=0,!0}update(){return!0}choose(){for(let e=this.roundId;e<this.roundWeights.length;e++){this.roundId=e;for(let t=this.workerNodeId;t<this.pool.workerNodes.length;t++){this.workerNodeId=t,this.workerNodeId!==this.nextWorkerNodeKey&&0!==this.workerNodeVirtualTaskRunTime&&(this.workerNodeVirtualTaskRunTime=0);const s=this.opts.weights?.[t]??this.defaultWorkerWeight;if(s>=this.roundWeights[e]&&this.workerNodeVirtualTaskRunTime<s)return this.workerNodeVirtualTaskRunTime=this.workerNodeVirtualTaskRunTime+this.getWorkerNodeTaskRunTime(t),this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=t,this.nextWorkerNodeKey}}this.interleavedWeightedRoundRobinNextWorkerNodeId()}interleavedWeightedRoundRobinNextWorkerNodeId(){this.roundId===this.roundWeights.length-1&&this.workerNodeId===this.pool.workerNodes.length-1?(this.roundId=0,this.workerNodeId=0):this.workerNodeId===this.pool.workerNodes.length-1?(this.roundId=this.roundId+1,this.workerNodeId=0):this.workerNodeId=this.workerNodeId+1}remove(e){return 0===this.pool.workerNodes.length&&this.reset(),this.workerNodeId===e&&this.workerNodeId>this.pool.workerNodes.length-1&&(this.workerNodeId=this.pool.workerNodes.length-1),this.previousWorkerNodeKey===e&&this.previousWorkerNodeKey>this.pool.workerNodes.length-1&&(this.previousWorkerNodeKey=this.pool.workerNodes.length-1),!0}setOptions(e){super.setOptions(e),this.roundWeights=this.getRoundWeights()}getRoundWeights(){return null==this.opts.weights?[this.defaultWorkerWeight]:[...new Set(Object.values(this.opts.weights).slice().sort(((e,t)=>e-t)))]}}class B extends Q{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:w};constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastBusyNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastBusyNextWorkerNodeKey(){return this.pool.workerNodes.reduce(((e,t,s,r)=>(t.usage.runTime.aggregate??0)+(t.usage.waitTime.aggregate??0)<(r[e].usage.runTime.aggregate??0)+(r[e].usage.waitTime.aggregate??0)?s:e),0)}}class U extends Q{constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastUsedNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastUsedNextWorkerNodeKey(){return this.pool.workerNodes.reduce(((e,t,s,r)=>t.usage.tasks.executed+t.usage.tasks.executing+t.usage.tasks.queued<r[e].usage.tasks.executed+r[e].usage.tasks.executing+r[e].usage.tasks.queued?s:e),0)}}class A extends Q{taskStatisticsRequirements={runTime:w,waitTime:w,elu:{aggregate:!0,average:!1,median:!1}};constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastEluNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastEluNextWorkerNodeKey(){return this.pool.workerNodes.reduce(((e,t,s,r)=>(t.usage.elu.active.aggregate??0)<(r[e].usage.elu.active.aggregate??0)?s:e),0)}}class D extends Q{constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.resetWorkerNodeKeyProperties(),!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;return this.setPreviousWorkerNodeKey(e),this.roundRobinNextWorkerNodeKey(),e}remove(e){return 0===this.pool.workerNodes.length&&this.reset(),this.nextWorkerNodeKey===e&&this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1),this.previousWorkerNodeKey===e&&this.previousWorkerNodeKey>this.pool.workerNodes.length-1&&(this.previousWorkerNodeKey=this.pool.workerNodes.length-1),!0}roundRobinNextWorkerNodeKey(){return this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,this.nextWorkerNodeKey}}class L extends Q{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:w,elu:w};defaultWorkerWeight;workerNodeVirtualTaskRunTime=0;constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight()}reset(){return this.resetWorkerNodeKeyProperties(),this.workerNodeVirtualTaskRunTime=0,!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.weightedRoundRobinNextWorkerNodeKey()}remove(e){return 0===this.pool.workerNodes.length&&this.reset(),this.nextWorkerNodeKey===e&&(this.workerNodeVirtualTaskRunTime=0,this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1)),this.previousWorkerNodeKey===e&&this.previousWorkerNodeKey>this.pool.workerNodes.length-1&&(this.previousWorkerNodeKey=this.pool.workerNodes.length-1),!0}weightedRoundRobinNextWorkerNodeKey(){const e=this.opts.weights?.[this.nextWorkerNodeKey??this.previousWorkerNodeKey]??this.defaultWorkerWeight;return this.workerNodeVirtualTaskRunTime<e?this.workerNodeVirtualTaskRunTime=this.workerNodeVirtualTaskRunTime+this.getWorkerNodeTaskRunTime(this.nextWorkerNodeKey??this.previousWorkerNodeKey):(this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,this.workerNodeVirtualTaskRunTime=0),this.nextWorkerNodeKey}}class _{workerChoiceStrategy;opts;workerChoiceStrategies;retriesCount=0;constructor(e,t=C.ROUND_ROBIN,s=p){this.workerChoiceStrategy=t,this.opts=s,this.opts={...p,...s},this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[C.ROUND_ROBIN,new(D.bind(this))(e,s)],[C.LEAST_USED,new(U.bind(this))(e,s)],[C.LEAST_BUSY,new(B.bind(this))(e,s)],[C.LEAST_ELU,new(A.bind(this))(e,s)],[C.FAIR_SHARE,new(K.bind(this))(e,s)],[C.WEIGHTED_ROUND_ROBIN,new(L.bind(this))(e,s)],[C.INTERLEAVED_WEIGHTED_ROUND_ROBIN,new(q.bind(this))(e,s)]])}getStrategyPolicy(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).strategyPolicy}getTaskStatisticsRequirements(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).taskStatisticsRequirements}setWorkerChoiceStrategy(e){this.workerChoiceStrategy!==e&&(this.workerChoiceStrategy=e),this.workerChoiceStrategies.get(this.workerChoiceStrategy)?.reset()}update(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).update(e)}execute(){const e=this.workerChoiceStrategies.get(this.workerChoiceStrategy).choose();if(null==e&&this.retriesCount<this.opts.retries)return this.retriesCount++,this.execute();if(null==e)throw new Error(`Worker node key chosen is null or undefined after ${this.retriesCount} retries`);return this.retriesCount=0,e}remove(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).remove(e)}setOptions(e){this.opts={...p,...e};for(const t of this.workerChoiceStrategies.values())t.setOptions(e)}}class j extends Array{size;constructor(e=1024,...t){super(),this.checkSize(e),this.size=e,arguments.length>1&&this.push(...t)}push(...e){const t=super.push(...e);return t>this.size&&super.splice(0,t-this.size),this.length}unshift(...e){return super.unshift(...e)>this.size&&super.splice(this.size,e.length),this.length}concat(...e){const t=super.concat(e);return t.size=this.size,t.length>t.size&&t.splice(0,t.length-t.size),t}splice(e,t,...s){let r=[];if(arguments.length>=3&&null!=t){if(r=super.splice(e,t,...s),this.length>this.size){const e=super.splice(0,this.length-this.size);r=new j(r.length+e.length,...r,...e)}}else r=2===arguments.length?super.splice(e,t):super.splice(e);return r}resize(e){if(this.checkSize(e),0===e)this.length=0;else if(e<this.size)for(let t=e;t<this.size;t++)super.pop();this.size=e}empty(){return 0===this.length}full(){return this.length===this.size}checkSize(e){if(!Number.isSafeInteger(e))throw new TypeError(`Invalid circular array size: ${e} is not a safe integer`);if(e<0)throw new RangeError(`Invalid circular array size: ${e} < 0`)}}class H{data;next;prev;constructor(e){this.data=e}}class V{head;tail;size;maxSize;constructor(){this.clear()}push(e){const t=new H(e);return null==this.tail?this.head=this.tail=t:(t.prev=this.tail,this.tail=this.tail.next=t),this.incrementSize()}unshift(e){const t=new H(e);return null==this.head?this.head=this.tail=t:(t.next=this.head,this.head=this.head.prev=t),this.incrementSize()}pop(){if(null==this.head)return;const e=this.tail;return this.tail=this.tail.prev,null==this.tail?this.head=void 0:this.tail.next=void 0,--this.size,e?.data}shift(){if(null==this.head)return;const e=this.head;return this.head=this.head.next,null==this.head?this.tail=void 0:this.head.prev=void 0,--this.size,e?.data}peekFirst(){return this.head?.data}peekLast(){return this.tail?.data}clear(){this.head=void 0,this.tail=void 0,this.size=0,this.maxSize=0}[Symbol.iterator](){let e=this.head;return{next:()=>{if(null==e)return{value:void 0,done:!0};const t={value:e.data,done:!1};return e=e.next,t}}}backward(){return{[Symbol.iterator]:()=>{let e=this.tail;return{next:()=>{if(null==e)return{value:void 0,done:!0};const t={value:e.data,done:!1};return e=e.prev,t}}}}}incrementSize(){return++this.size,this.size>this.maxSize&&(this.maxSize=this.size),this.size}}class ${worker;info;usage;strategyData;messageChannel;tasksQueueBackPressureSize;onBackPressure;onEmptyQueue;tasksQueue;onBackPressureStarted;onEmptyQueueCount;taskFunctionsUsage;constructor(e,s){((e,t)=>{if(null==e)throw new TypeError("Cannot construct a worker node without a worker");if(null==t)throw new TypeError("Cannot construct a worker node without a tasks queue back pressure size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot construct a worker node with a tasks queue back pressure size that is not an integer");if(t<=0)throw new RangeError("Cannot construct a worker node with a tasks queue back pressure size that is not a positive integer")})(e,s),this.worker=e,this.info=this.initWorkerInfo(e),this.usage=this.initWorkerUsage(),this.info.type===l.thread&&(this.messageChannel=new t.MessageChannel),this.tasksQueueBackPressureSize=s,this.tasksQueue=new V,this.onBackPressureStarted=!1,this.onEmptyQueueCount=0,this.taskFunctionsUsage=new Map}tasksQueueSize(){return this.tasksQueue.size}enqueueTask(e){const t=this.tasksQueue.push(e);return null!=this.onBackPressure&&this.hasBackPressure()&&!this.onBackPressureStarted&&(this.onBackPressureStarted=!0,this.onBackPressure(this.info.id),this.onBackPressureStarted=!1),t}unshiftTask(e){const t=this.tasksQueue.unshift(e);return null!=this.onBackPressure&&this.hasBackPressure()&&!this.onBackPressureStarted&&(this.onBackPressureStarted=!0,this.onBackPressure(this.info.id),this.onBackPressureStarted=!1),t}dequeueTask(){const e=this.tasksQueue.shift();return null!=this.onEmptyQueue&&0===this.tasksQueue.size&&0===this.onEmptyQueueCount&&this.startOnEmptyQueue().catch(m),e}popTask(){const e=this.tasksQueue.pop();return null!=this.onEmptyQueue&&0===this.tasksQueue.size&&0===this.onEmptyQueueCount&&this.startOnEmptyQueue().catch(m),e}clearTasksQueue(){this.tasksQueue.clear()}hasBackPressure(){return this.tasksQueue.size>=this.tasksQueueBackPressureSize}resetUsage(){this.usage=this.initWorkerUsage(),this.taskFunctionsUsage.clear()}closeChannel(){null!=this.messageChannel&&(this.messageChannel?.port1.unref(),this.messageChannel?.port2.unref(),this.messageChannel?.port1.close(),this.messageChannel?.port2.close(),delete this.messageChannel)}getTaskFunctionWorkerUsage(e){if(!Array.isArray(this.info.taskFunctionNames))throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function names list is not yet defined`);if(Array.isArray(this.info.taskFunctionNames)&&this.info.taskFunctionNames.length<3)throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function names list has less than 3 elements`);return e===g&&(e=this.info.taskFunctionNames[1]),this.taskFunctionsUsage.has(e)||this.taskFunctionsUsage.set(e,this.initTaskFunctionWorkerUsage(e)),this.taskFunctionsUsage.get(e)}deleteTaskFunctionWorkerUsage(e){return this.taskFunctionsUsage.delete(e)}async startOnEmptyQueue(){this.onEmptyQueueCount>0&&(this.usage.tasks.executing>0||this.tasksQueue.size>0)?this.onEmptyQueueCount=0:(++this.onEmptyQueueCount,this.onEmptyQueue?.(this.info.id),await(async e=>{await new Promise((t=>{setTimeout(t,e)}))})(((e=0,t=100)=>{const s=Math.pow(2,e)*t;return s+.2*s*v()})(this.onEmptyQueueCount)),await this.startOnEmptyQueue())}initWorkerInfo(e){return{id:T(e),type:y(e),dynamic:!1,ready:!1}}initWorkerUsage(){const e=()=>this.tasksQueue.size,t=()=>this.tasksQueue.maxSize;return{tasks:{executed:0,executing:0,get queued(){return e()},get maxQueued(){return t()},stolen:0,failed:0},runTime:{history:new j},waitTime:{history:new j},elu:{idle:{history:new j},active:{history:new j}}}}initTaskFunctionWorkerUsage(e){const t=()=>{let t=0;for(const s of this.tasksQueue)(s.name===g&&e===this.info.taskFunctionNames[1]||s.name!==g&&e===s.name)&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},stolen:0,failed:0},runTime:{history:new j},waitTime:{history:new j},elu:{idle:{history:new j},active:{history:new j}}}}}class G{numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;max;taskFunctions;started;starting;startTimestamp;constructor(e,t,r){if(this.numberOfWorkers=e,this.filePath=t,this.opts=r,!this.isMain())throw new Error("Cannot start a pool from a worker with the same type as the pool");this.checkNumberOfWorkers(this.numberOfWorkers),(e=>{if(null==e||"string"!=typeof e||"string"==typeof e&&0===e.trim().length)throw new Error("Please specify a file with a worker implementation");if(!s.existsSync(e))throw new Error(`Cannot find the worker file '${e}'`)})(this.filePath),this.checkPoolOptions(this.opts),this.chooseWorkerNode=this.chooseWorkerNode.bind(this),this.executeTask=this.executeTask.bind(this),this.enqueueTask=this.enqueueTask.bind(this),!0===this.opts.enableEvents&&(this.emitter=new c),this.workerChoiceStrategyContext=new _(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook(),this.taskFunctions=new Map,this.started=!1,this.starting=!1,!0===this.opts.startWorkers&&this.start(),this.startTimestamp=n.performance.now()}checkNumberOfWorkers(e){if(null==e)throw new Error("Cannot instantiate a pool without specifying the number of workers");if(!Number.isSafeInteger(e))throw new TypeError("Cannot instantiate a pool with a non safe integer number of workers");if(e<0)throw new RangeError("Cannot instantiate a pool with a negative number of workers");if(this.type===k.fixed&&0===e)throw new RangeError("Cannot instantiate a fixed pool with zero worker")}checkPoolOptions(e){if(!S(e))throw new TypeError("Invalid pool options: must be a plain object");this.opts.startWorkers=e.startWorkers??!0,R(e.workerChoiceStrategy),this.opts.workerChoiceStrategy=e.workerChoiceStrategy??C.ROUND_ROBIN,this.checkValidWorkerChoiceStrategyOptions(e.workerChoiceStrategyOptions),this.opts.workerChoiceStrategyOptions={...p,...e.workerChoiceStrategyOptions},this.opts.restartWorkerOnError=e.restartWorkerOnError??!0,this.opts.enableEvents=e.enableEvents??!0,this.opts.enableTasksQueue=e.enableTasksQueue??!1,this.opts.enableTasksQueue&&(z(e.tasksQueueOptions),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e.tasksQueueOptions))}checkValidWorkerChoiceStrategyOptions(e){if(null!=e&&!S(e))throw new TypeError("Invalid worker choice strategy options: must be a plain object");if(null!=e?.retries&&!Number.isSafeInteger(e.retries))throw new TypeError("Invalid worker choice strategy options: retries must be an integer");if(null!=e?.retries&&e.retries<0)throw new RangeError(`Invalid worker choice strategy options: retries '${e.retries}' must be greater or equal than zero`);if(null!=e?.weights&&Object.keys(e.weights).length!==this.maxSize)throw new Error("Invalid worker choice strategy options: must have a weight for each worker node");if(null!=e?.measurement&&!Object.values(O).includes(e.measurement))throw new Error(`Invalid worker choice strategy options: invalid measurement '${e.measurement}'`)}get info(){return{version:"2.7.1",type:this.type,worker:this.worker,started:this.started,ready:this.ready,strategy:this.opts.workerChoiceStrategy,minSize:this.minSize,maxSize:this.maxSize,...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{utilization:W(this.utilization)},workerNodes:this.workerNodes.length,idleWorkerNodes:this.workerNodes.reduce(((e,t)=>0===t.usage.tasks.executing?e+1:e),0),busyWorkerNodes:this.workerNodes.reduce(((e,t)=>t.usage.tasks.executing>0?e+1:e),0),executedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executed),0),executingTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executing),0),...!0===this.opts.enableTasksQueue&&{queuedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.queued),0)},...!0===this.opts.enableTasksQueue&&{maxQueuedTasks:this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.maxQueued??0)),0)},...!0===this.opts.enableTasksQueue&&{backPressure:this.hasBackPressure()},...!0===this.opts.enableTasksQueue&&{stolenTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.stolen),0)},failedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.failed),0),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&{runTime:{minimum:W(b(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:W(I(...this.workerNodes.map((e=>e.usage.runTime?.maximum??-1/0)))),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.average&&{average:W(f(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&{median:W(N(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:W(b(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:W(I(...this.workerNodes.map((e=>e.usage.waitTime?.maximum??-1/0)))),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.average&&{average:W(f(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.waitTime.history)),[])))},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&{median:W(N(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.waitTime.history)),[])))}}}}}get ready(){return this.workerNodes.reduce(((e,t)=>!t.info.dynamic&&t.info.ready?e+1:e),0)>=this.minSize}get utilization(){const e=(n.performance.now()-this.startTimestamp)*this.maxSize;return(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)+this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0))/e}get minSize(){return this.numberOfWorkers}get maxSize(){return this.max??this.numberOfWorkers}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Worker message received without worker id");if(null!=e.workerId&&-1===this.getWorkerNodeKeyByWorkerId(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKeyByWorker(e){return this.workerNodes.findIndex((t=>t.worker===e))}getWorkerNodeKeyByWorkerId(e){return this.workerNodes.findIndex((t=>t.info.id===e))}setWorkerChoiceStrategy(e,t){R(e),this.opts.workerChoiceStrategy=e,this.workerChoiceStrategyContext.setWorkerChoiceStrategy(this.opts.workerChoiceStrategy),null!=t&&this.setWorkerChoiceStrategyOptions(t);for(const[e,t]of this.workerNodes.entries())t.resetUsage(),this.sendStatisticsMessageToWorker(e)}setWorkerChoiceStrategyOptions(e){this.checkValidWorkerChoiceStrategyOptions(e),this.opts.workerChoiceStrategyOptions={...p,...e},this.workerChoiceStrategyContext.setOptions(this.opts.workerChoiceStrategyOptions)}enableTasksQueue(e,t){!0!==this.opts.enableTasksQueue||e||(this.unsetTaskStealing(),this.unsetTasksStealingOnBackPressure(),this.flushTasksQueues()),this.opts.enableTasksQueue=e,this.setTasksQueueOptions(t)}setTasksQueueOptions(e){!0===this.opts.enableTasksQueue?(z(e),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e),this.setTasksQueueSize(this.opts.tasksQueueOptions.size),!0===this.opts.tasksQueueOptions.taskStealing?this.setTaskStealing():this.unsetTaskStealing(),!0===this.opts.tasksQueueOptions.tasksStealingOnBackPressure?this.setTasksStealingOnBackPressure():this.unsetTasksStealingOnBackPressure()):null!=this.opts.tasksQueueOptions&&delete this.opts.tasksQueueOptions}buildTasksQueueOptions(e){return{size:Math.pow(this.maxSize,2),concurrency:1,taskStealing:!0,tasksStealingOnBackPressure:!0,...e}}setTasksQueueSize(e){for(const t of this.workerNodes)t.tasksQueueBackPressureSize=e}setTaskStealing(){for(const[e]of this.workerNodes.entries())this.workerNodes[e].onEmptyQueue=this.taskStealingOnEmptyQueue.bind(this)}unsetTaskStealing(){for(const[e]of this.workerNodes.entries())delete this.workerNodes[e].onEmptyQueue}setTasksStealingOnBackPressure(){for(const[e]of this.workerNodes.entries())this.workerNodes[e].onBackPressure=this.tasksStealingOnBackPressure.bind(this)}unsetTasksStealingOnBackPressure(){for(const[e]of this.workerNodes.entries())delete this.workerNodes[e].onBackPressure}get full(){return this.workerNodes.length>=this.maxSize}internalBusy(){return!0===this.opts.enableTasksQueue?-1===this.workerNodes.findIndex((e=>e.info.ready&&e.usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency)):-1===this.workerNodes.findIndex((e=>e.info.ready&&0===e.usage.tasks.executing))}async sendTaskFunctionOperationToWorker(e,t){return await new Promise(((s,r)=>{const i=t=>{this.checkMessageWorkerId(t);const o=this.getWorkerInfo(e).id;null!=t.taskFunctionOperationStatus&&t.workerId===o&&(t.taskFunctionOperationStatus?s(!0):t.taskFunctionOperationStatus||r(new Error(`Task function operation '${t.taskFunctionOperation}' failed on worker ${t.workerId} with error: '${t.workerError?.message}'`)),this.deregisterWorkerMessageListener(this.getWorkerNodeKeyByWorkerId(t.workerId),i))};this.registerWorkerMessageListener(e,i),this.sendToWorker(e,t)}))}async sendTaskFunctionOperationToWorkers(e){return await new Promise(((t,s)=>{const r=new Array,i=e=>{if(this.checkMessageWorkerId(e),null!=e.taskFunctionOperationStatus&&(r.push(e),r.length===this.workerNodes.length)){if(r.every((e=>!0===e.taskFunctionOperationStatus)))t(!0);else if(r.some((e=>!1===e.taskFunctionOperationStatus))){const t=r.find((e=>!1===e.taskFunctionOperationStatus));s(new Error(`Task function operation '${e.taskFunctionOperation}' failed on worker ${t?.workerId} with error: '${t?.workerError?.message}'`))}this.deregisterWorkerMessageListener(this.getWorkerNodeKeyByWorkerId(e.workerId),i)}};for(const[t]of this.workerNodes.entries())this.registerWorkerMessageListener(t,i),this.sendToWorker(t,e)}))}hasTaskFunction(e){for(const t of this.workerNodes)if(Array.isArray(t.info.taskFunctionNames)&&t.info.taskFunctionNames.includes(e))return!0;return!1}async addTaskFunction(e,t){if("string"!=typeof e)throw new TypeError("name argument must be a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("name argument must not be an empty string");if("function"!=typeof t)throw new TypeError("fn argument must be a function");const s=await this.sendTaskFunctionOperationToWorkers({taskFunctionOperation:"add",taskFunctionName:e,taskFunction:t.toString()});return this.taskFunctions.set(e,t),s}async removeTaskFunction(e){if(!this.taskFunctions.has(e))throw new Error("Cannot remove a task function not handled on the pool side");const t=await this.sendTaskFunctionOperationToWorkers({taskFunctionOperation:"remove",taskFunctionName:e});return this.deleteTaskFunctionWorkerUsages(e),this.taskFunctions.delete(e),t}listTaskFunctionNames(){for(const e of this.workerNodes)if(Array.isArray(e.info.taskFunctionNames)&&e.info.taskFunctionNames.length>0)return e.info.taskFunctionNames;return[]}async setDefaultTaskFunction(e){return await this.sendTaskFunctionOperationToWorkers({taskFunctionOperation:"default",taskFunctionName:e})}deleteTaskFunctionWorkerUsages(e){for(const t of this.workerNodes)t.deleteTaskFunctionWorkerUsage(e)}shallExecuteTask(e){return 0===this.tasksQueueSize(e)&&this.workerNodes[e].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency}async execute(e,t,s){return await new Promise(((r,o)=>{if(!this.started)return void o(new Error("Cannot execute a task on not started pool"));if(null!=t&&"string"!=typeof t)return void o(new TypeError("name argument must be a string"));if(null!=t&&"string"==typeof t&&0===t.trim().length)return void o(new TypeError("name argument must not be an empty string"));if(null!=s&&!Array.isArray(s))return void o(new TypeError("transferList argument must be an array"));const a=n.performance.now(),u=this.chooseWorkerNode(),h={name:t??g,data:e??{},transferList:s,timestamp:a,taskId:i.randomUUID()};this.promiseResponseMap.set(h.taskId,{resolve:r,reject:o,workerNodeKey:u}),!1===this.opts.enableTasksQueue||!0===this.opts.enableTasksQueue&&this.shallExecuteTask(u)?this.executeTask(u,h):this.enqueueTask(u,h)}))}start(){for(this.starting=!0;this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.numberOfWorkers;)this.createAndSetupWorkerNode();this.starting=!1,this.started=!0}async destroy(){await Promise.all(this.workerNodes.map((async(e,t)=>{await this.destroyWorkerNode(t)}))),this.emitter?.emit(d.destroy,this.info),this.started=!1}async sendKillMessageToWorker(e){await new Promise(((t,s)=>{this.registerWorkerMessageListener(e,(e=>{this.checkMessageWorkerId(e),"success"===e.kill?t():"failure"===e.kill&&s(new Error(`Kill message handling failed on worker ${e.workerId}`))})),this.sendToWorker(e,{kill:!0})}))}setupHook(){}beforeTaskExecutionHook(e,t){if(null!=this.workerNodes[e]?.usage){const s=this.workerNodes[e].usage;++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t)}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name)){const s=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name);++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t)}}afterTaskExecutionHook(e,t){if(null!=this.workerNodes[e]?.usage){const s=this.workerNodes[e].usage;this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t)}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance?.name)){const s=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance?.name);this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t)}}shallUpdateTaskFunctionWorkerUsage(e){const t=this.getWorkerInfo(e);return null!=t&&Array.isArray(t.taskFunctionNames)&&t.taskFunctionNames.length>2}updateTaskStatisticsWorkerUsage(e,t){const s=e.tasks;null!=s.executing&&s.executing>0&&--s.executing,null==t.workerError?++s.executed:++s.failed}updateRunTimeWorkerUsage(e,t){null==t.workerError&&P(e.runTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime,t.taskPerformance?.runTime??0)}updateWaitTimeWorkerUsage(e,t){const s=n.performance.now(),r=s-(t.timestamp??s);P(e.waitTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime,r)}updateEluWorkerUsage(e,t){if(null!=t.workerError)return;const s=this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu;P(e.elu.active,s,t.taskPerformance?.elu?.active??0),P(e.elu.idle,s,t.taskPerformance?.elu?.idle??0),s.aggregate&&null!=t.taskPerformance?.elu&&(null!=e.elu.utilization?e.elu.utilization=(e.elu.utilization+t.taskPerformance.elu.utilization)/2:e.elu.utilization=t.taskPerformance.elu.utilization)}chooseWorkerNode(){if(this.shallCreateDynamicWorker()){const e=this.createAndSetupDynamicWorkerNode();if(this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerUsage)return e}return this.workerChoiceStrategyContext.execute()}shallCreateDynamicWorker(){return this.type===k.dynamic&&!this.full&&this.internalBusy()}createAndSetupWorkerNode(){const e=this.createWorker();e.on("online",this.opts.onlineHandler??m),e.on("message",this.opts.messageHandler??m),e.on("error",this.opts.errorHandler??m),e.on("error",(t=>{const s=this.getWorkerNodeKeyByWorker(e),r=this.getWorkerInfo(s);r.ready=!1,this.workerNodes[s].closeChannel(),this.emitter?.emit(d.error,t),this.started&&!this.starting&&!0===this.opts.restartWorkerOnError&&(r.dynamic?this.createAndSetupDynamicWorkerNode():this.createAndSetupWorkerNode()),this.started&&!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(s)})),e.on("exit",this.opts.exitHandler??m),e.once("exit",(()=>{this.removeWorkerNode(e)}));const t=this.addWorkerNode(e);return this.afterWorkerNodeSetup(t),t}createAndSetupDynamicWorkerNode(){const e=this.createAndSetupWorkerNode();this.registerWorkerMessageListener(e,(e=>{this.checkMessageWorkerId(e);const t=this.getWorkerNodeKeyByWorkerId(e.workerId),s=this.workerNodes[t].usage;(x(M.HARD,e.kill)||x(M.SOFT,e.kill)&&(!1===this.opts.enableTasksQueue&&0===s.tasks.executing||!0===this.opts.enableTasksQueue&&0===s.tasks.executing&&0===this.tasksQueueSize(t)))&&this.destroyWorkerNode(t).catch((e=>{this.emitter?.emit(d.error,e)}))}));const t=this.getWorkerInfo(e);if(this.sendToWorker(e,{checkActive:!0}),this.taskFunctions.size>0)for(const[t,s]of this.taskFunctions)this.sendTaskFunctionOperationToWorker(e,{taskFunctionOperation:"add",taskFunctionName:t,taskFunction:s.toString()}).catch((e=>{this.emitter?.emit(d.error,e)}));return t.dynamic=!0,(this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerReady||this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerUsage)&&(t.ready=!0),this.checkAndEmitDynamicWorkerCreationEvents(),e}afterWorkerNodeSetup(e){this.registerWorkerMessageListener(e,this.workerListener()),this.sendStartupMessageToWorker(e),this.sendStatisticsMessageToWorker(e),!0===this.opts.enableTasksQueue&&(!0===this.opts.tasksQueueOptions?.taskStealing&&(this.workerNodes[e].onEmptyQueue=this.taskStealingOnEmptyQueue.bind(this)),!0===this.opts.tasksQueueOptions?.tasksStealingOnBackPressure&&(this.workerNodes[e].onBackPressure=this.tasksStealingOnBackPressure.bind(this)))}sendStatisticsMessageToWorker(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate}})}redistributeQueuedTasks(e){for(;this.tasksQueueSize(e)>0;){const t=this.workerNodes.reduce(((e,t,s,r)=>t.info.ready&&t.usage.tasks.queued<r[e].usage.tasks.queued?s:e),0),s=this.dequeueTask(e);this.shallExecuteTask(t)?this.executeTask(t,s):this.enqueueTask(t,s)}}updateTaskStolenStatisticsWorkerUsage(e,t){const s=this.workerNodes[e];if(null!=s?.usage&&++s.usage.tasks.stolen,this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=s.getTaskFunctionWorkerUsage(t)){++s.getTaskFunctionWorkerUsage(t).tasks.stolen}}taskStealingOnEmptyQueue(e){const t=this.getWorkerNodeKeyByWorkerId(e),s=this.workerNodes.slice().sort(((e,t)=>t.usage.tasks.queued-e.usage.tasks.queued)).find((t=>t.info.ready&&t.info.id!==e&&t.usage.tasks.queued>0));if(null!=s){const e=s.popTask();this.shallExecuteTask(t)?this.executeTask(t,e):this.enqueueTask(t,e),this.updateTaskStolenStatisticsWorkerUsage(t,e.name)}}tasksStealingOnBackPressure(e){if(this.opts.tasksQueueOptions?.size<=1)return;const t=this.workerNodes[this.getWorkerNodeKeyByWorkerId(e)],s=this.workerNodes.slice().sort(((e,t)=>e.usage.tasks.queued-t.usage.tasks.queued));for(const[r,i]of s.entries())if(t.usage.tasks.queued>0&&i.info.ready&&i.info.id!==e&&i.usage.tasks.queued<this.opts.tasksQueueOptions?.size-1){const e=t.popTask();this.shallExecuteTask(r)?this.executeTask(r,e):this.enqueueTask(r,e),this.updateTaskStolenStatisticsWorkerUsage(r,e.name)}}workerListener(){return e=>{this.checkMessageWorkerId(e),null!=e.ready&&null!=e.taskFunctionNames?this.handleWorkerReadyResponse(e):null!=e.taskId?this.handleTaskExecutionResponse(e):null!=e.taskFunctionNames&&(this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId)).taskFunctionNames=e.taskFunctionNames)}}handleWorkerReadyResponse(e){if(!1===e.ready)throw new Error(`Worker ${e.workerId} failed to initialize`);const t=this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId));t.ready=e.ready,t.taskFunctionNames=e.taskFunctionNames,this.ready&&this.emitter?.emit(d.ready,this.info)}handleTaskExecutionResponse(e){const{taskId:t,workerError:s,data:r}=e,i=this.promiseResponseMap.get(t);if(null!=i){null!=s?(this.emitter?.emit(d.taskError,s),i.reject(s.message)):i.resolve(r);const o=i.workerNodeKey;this.afterTaskExecutionHook(o,e),this.workerChoiceStrategyContext.update(o),this.promiseResponseMap.delete(t),!0===this.opts.enableTasksQueue&&this.tasksQueueSize(o)>0&&this.workerNodes[o].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&this.executeTask(o,this.dequeueTask(o))}}checkAndEmitTaskExecutionEvents(){this.busy&&this.emitter?.emit(d.busy,this.info)}checkAndEmitTaskQueuingEvents(){this.hasBackPressure()&&this.emitter?.emit(d.backPressure,this.info)}checkAndEmitDynamicWorkerCreationEvents(){this.type===k.dynamic&&this.full&&this.emitter?.emit(d.full,this.info)}getWorkerInfo(e){return this.workerNodes[e].info}addWorkerNode(e){const t=new $(e,this.opts.tasksQueueOptions?.size??Math.pow(this.maxSize,2));this.starting&&(t.info.ready=!0),this.workerNodes.push(t);const s=this.getWorkerNodeKeyByWorker(e);if(-1===s)throw new Error("Worker added not found in worker nodes");return s}removeWorkerNode(e){const t=this.getWorkerNodeKeyByWorker(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategyContext.remove(t))}hasWorkerNodeBackPressure(e){return!0===this.opts.enableTasksQueue&&this.workerNodes[e].hasBackPressure()}hasBackPressure(){return!0===this.opts.enableTasksQueue&&-1===this.workerNodes.findIndex((e=>!e.hasBackPressure()))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(e,t,t.transferList),this.checkAndEmitTaskExecutionEvents()}enqueueTask(e,t){const s=this.workerNodes[e].enqueueTask(t);return this.checkAndEmitTaskQueuingEvents(),s}dequeueTask(e){return this.workerNodes[e].dequeueTask()}tasksQueueSize(e){return this.workerNodes[e].tasksQueueSize()}flushTasksQueue(e){for(;this.tasksQueueSize(e)>0;)this.executeTask(e,this.dequeueTask(e));this.workerNodes[e].clearTasksQueue()}flushTasksQueues(){for(const[e]of this.workerNodes.entries())this.flushTasksQueue(e)}}class Y extends G{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}setupHook(){o.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return o.isPrimary}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e].worker,s=new Promise((e=>{t.once("exit",(()=>{e()}))}));t.once("disconnect",(()=>{t.kill()})),await this.sendKillMessageToWorker(e),t.disconnect(),await s}sendToWorker(e,t){this.workerNodes[e].worker.send({...t,workerId:this.workerNodes[e].info.id})}sendStartupMessageToWorker(e){this.sendToWorker(e,{ready:!1})}registerWorkerMessageListener(e,t){this.workerNodes[e].worker.on("message",t)}registerOnceWorkerMessageListener(e,t){this.workerNodes[e].worker.once("message",t)}deregisterWorkerMessageListener(e,t){this.workerNodes[e].worker.off("message",t)}createWorker(){return o.fork(this.opts.env)}get type(){return k.fixed}get worker(){return l.cluster}get busy(){return this.internalBusy()}}class J extends G{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}isMain(){return t.isMainThread}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e],s=t.worker,r=new Promise((e=>{s.once("exit",(()=>{e()}))}));await this.sendKillMessageToWorker(e),t.closeChannel(),await s.terminate(),await r}sendToWorker(e,t,s){this.workerNodes[e].messageChannel.port1.postMessage({...t,workerId:this.workerNodes[e].info.id},s)}sendStartupMessageToWorker(e){const t=this.workerNodes[e],s=t.messageChannel.port2;t.worker.postMessage({ready:!1,workerId:t.info.id,port:s},[s])}registerWorkerMessageListener(e,t){this.workerNodes[e].messageChannel.port1.on("message",t)}registerOnceWorkerMessageListener(e,t){this.workerNodes[e].messageChannel.port1.once("message",t)}deregisterWorkerMessageListener(e,t){this.workerNodes[e].messageChannel.port1.off("message",t)}createWorker(){return new t.Worker(this.filePath,{env:t.SHARE_ENV,...this.opts.workerOptions})}get type(){return k.fixed}get worker(){return l.thread}get busy(){return this.internalBusy()}}const X=(e,t)=>{if("string"!=typeof e)throw new TypeError("A taskFunctions parameter object key is not a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("A taskFunctions parameter object key is an empty string");if("function"!=typeof t)throw new TypeError("A taskFunctions parameter object value is not a function")},Z=e=>{if("string"!=typeof e)throw new TypeError("name parameter is not a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("name parameter is an empty string")},ee=6e4,te={killBehavior:M.SOFT,maxInactiveTime:ee,killHandler:m};class se extends a.AsyncResource{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,s,r,i=te){if(super(e),this.isMain=t,this.mainWorker=s,this.opts=i,null==this.isMain)throw new Error("isMain parameter is mandatory");this.checkTaskFunctions(r),this.checkWorkerOptions(this.opts),this.isMain||this.getMainWorker().on("message",this.handleReadyMessage.bind(this))}checkWorkerOptions(e){(e=>{if(null!=e&&!S(e))throw new TypeError("opts worker options parameter is not a plain object");if(null!=e?.killBehavior&&!Object.values(M).includes(e.killBehavior))throw new TypeError(`killBehavior option '${e.killBehavior}' is not valid`);if(null!=e?.maxInactiveTime&&!Number.isSafeInteger(e.maxInactiveTime))throw new TypeError("maxInactiveTime option is not an integer");if(null!=e?.maxInactiveTime&&e.maxInactiveTime<5)throw new TypeError("maxInactiveTime option is not a positive integer greater or equal than 5");if(null!=e?.killHandler&&"function"!=typeof e.killHandler)throw new TypeError("killHandler option is not a function");if(null!=e?.async)throw new Error("async option is deprecated")})(e),this.opts={...te,...e}}checkTaskFunctions(e){if(null==e)throw new Error("taskFunctions parameter is mandatory");if(this.taskFunctions=new Map,"function"==typeof e){const t=e.bind(this);this.taskFunctions.set(g,t),this.taskFunctions.set("string"==typeof e.name&&e.name.trim().length>0?e.name:"fn1",t)}else{if(!S(e))throw new TypeError("taskFunctions parameter is not a function or a plain object");{let t=!0;for(const[s,r]of Object.entries(e)){X(s,r);const e=r.bind(this);t&&(this.taskFunctions.set(g,e),t=!1),this.taskFunctions.set(s,e)}if(t)throw new Error("taskFunctions parameter object is empty")}}}hasTaskFunction(e){try{Z(e)}catch(e){return{status:!1,error:e}}return{status:this.taskFunctions.has(e)}}addTaskFunction(e,t){try{if(Z(e),e===g)throw new Error("Cannot add a task function with the default reserved name");if("function"!=typeof t)throw new TypeError("fn parameter is not a function");const s=t.bind(this);return this.taskFunctions.get(e)===this.taskFunctions.get(g)&&this.taskFunctions.set(g,s),this.taskFunctions.set(e,s),this.sendTaskFunctionNamesToMainWorker(),{status:!0}}catch(e){return{status:!1,error:e}}}removeTaskFunction(e){try{if(Z(e),e===g)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(g))throw new Error("Cannot remove the task function used as the default task function");const t=this.taskFunctions.delete(e);return this.sendTaskFunctionNamesToMainWorker(),{status:t}}catch(e){return{status:!1,error:e}}}listTaskFunctionNames(){const e=[...this.taskFunctions.keys()];let t=g;for(const[e,s]of this.taskFunctions)if(e!==g&&s===this.taskFunctions.get(g)){t=e;break}return[e[e.indexOf(g)],t,...e.filter((e=>e!==g&&e!==t))]}setDefaultTaskFunction(e){try{if(Z(e),e===g)throw new Error("Cannot set the default task function reserved name as the default task function");if(!this.taskFunctions.has(e))throw new Error("Cannot set the default task function to a non-existing task function");return this.taskFunctions.set(g,this.taskFunctions.get(e)),this.sendTaskFunctionNamesToMainWorker(),{status:!0}}catch(e){return{status:!1,error:e}}}messageListener(e){this.checkMessageWorkerId(e),null!=e.statistics?this.statistics=e.statistics:null!=e.checkActive?e.checkActive?this.startCheckActive():this.stopCheckActive():null!=e.taskFunctionOperation?this.handleTaskFunctionOperationMessage(e):null!=e.taskId&&null!=e.data?this.run(e):!0===e.kill&&this.handleKillMessage(e)}handleTaskFunctionOperationMessage(e){const{taskFunctionOperation:t,taskFunctionName:s,taskFunction:r}=e;let i;switch(t){case"add":i=this.addTaskFunction(s,new Function(`return ${r}`)());break;case"remove":i=this.removeTaskFunction(s);break;case"default":i=this.setDefaultTaskFunction(s);break;default:i={status:!1,error:new Error("Unknown task operation")}}this.sendToMainWorker({taskFunctionOperation:t,taskFunctionOperationStatus:i.status,taskFunctionName:s,...!i.status&&null!=i?.error&&{workerError:{name:s,message:this.handleError(i.error)}}})}handleKillMessage(e){if(this.stopCheckActive(),E(this.opts.killHandler))(this.opts.killHandler?.()).then((()=>(this.sendToMainWorker({kill:"success"}),null))).catch((()=>{this.sendToMainWorker({kill:"failure"})})).finally((()=>{this.emitDestroy()})).catch(m);else try{this.opts.killHandler?.(),this.sendToMainWorker({kill:"success"})}catch{this.sendToMainWorker({kill:"failure"})}finally{this.emitDestroy()}}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Message worker id is not set");if(null!=e.workerId&&e.workerId!==this.id)throw new Error(`Message worker id ${e.workerId} does not match the worker id ${this.id}`)}startCheckActive(){this.lastTaskTimestamp=n.performance.now(),this.activeInterval=setInterval(this.checkActive.bind(this),(this.opts.maxInactiveTime??ee)/2)}stopCheckActive(){null!=this.activeInterval&&(clearInterval(this.activeInterval),delete this.activeInterval)}checkActive(){n.performance.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??ee)&&this.sendToMainWorker({kill:this.opts.killBehavior})}getMainWorker(){if(null==this.mainWorker)throw new Error("Main worker not set");return this.mainWorker}sendTaskFunctionNamesToMainWorker(){this.sendToMainWorker({taskFunctionNames:this.listTaskFunctionNames()})}handleError(e){return e instanceof Error?e.message:e}run(e){const{name:t,taskId:s,data:r}=e,i=this.taskFunctions.get(t??g);null!=i?E(i)?this.runInAsyncScope(this.runAsync.bind(this),this,i,e):this.runInAsyncScope(this.runSync.bind(this),this,i,e):this.sendToMainWorker({workerError:{name:t,message:`Task function '${t}' not found`,data:r},taskId:s})}runSync(e,t){const{name:s,taskId:r,data:i}=t;try{let t=this.beginTaskPerformance(s);const o=e(i);t=this.endTaskPerformance(t),this.sendToMainWorker({data:o,taskPerformance:t,taskId:r})}catch(e){this.sendToMainWorker({workerError:{name:s,message:this.handleError(e),data:i},taskId:r})}finally{this.updateLastTaskTimestamp()}}runAsync(e,t){const{name:s,taskId:r,data:i}=t;let o=this.beginTaskPerformance(s);e(i).then((e=>{o=this.endTaskPerformance(o),this.sendToMainWorker({data:e,taskPerformance:o,taskId:r})})).catch((e=>{this.sendToMainWorker({workerError:{name:s,message:this.handleError(e),data:i},taskId:r})})).finally((()=>{this.updateLastTaskTimestamp()})).catch(m)}beginTaskPerformance(e){return this.checkStatistics(),{name:e??g,timestamp:n.performance.now(),...this.statistics.elu&&{elu:n.performance.eventLoopUtilization()}}}endTaskPerformance(e){return this.checkStatistics(),{...e,...this.statistics.runTime&&{runTime:n.performance.now()-e.timestamp},...this.statistics.elu&&{elu:n.performance.eventLoopUtilization(e.elu)}}}checkStatistics(){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set")}updateLastTaskTimestamp(){null!=this.activeInterval&&(this.lastTaskTimestamp=n.performance.now())}}exports.ClusterWorker=class extends se{constructor(e,t={}){super("worker-cluster-pool:poolifier",o.isPrimary,o.worker,e,t)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready)try{this.getMainWorker().on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctionNames:this.listTaskFunctionNames()})}catch{this.sendToMainWorker({ready:!1,taskFunctionNames:this.listTaskFunctionNames()})}}get id(){return this.getMainWorker().id}sendToMainWorker(e){this.getMainWorker().send({...e,workerId:this.id})}},exports.DynamicClusterPool=class extends Y{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,F(this.numberOfWorkers,this.max)}get type(){return k.dynamic}get busy(){return this.full&&this.internalBusy()}},exports.DynamicThreadPool=class extends J{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,F(this.numberOfWorkers,this.max)}get type(){return k.dynamic}get busy(){return this.full&&this.internalBusy()}},exports.FixedClusterPool=Y,exports.FixedThreadPool=J,exports.KillBehaviors=M,exports.Measurements=O,exports.PoolEvents=d,exports.PoolTypes=k,exports.ThreadWorker=class extends se{port;constructor(e,s={}){super("worker-thread-pool:poolifier",t.isMainThread,t.parentPort,e,s)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready&&null!=e.port)try{this.port=e.port,this.port.on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctionNames:this.listTaskFunctionNames()})}catch{this.sendToMainWorker({ready:!1,taskFunctionNames:this.listTaskFunctionNames()})}}handleKillMessage(e){super.handleKillMessage(e),this.port?.unref(),this.port?.close()}get id(){return t.threadId}sendToMainWorker(e){this.port.postMessage({...e,workerId:this.id})}handleError(e){return e}},exports.WorkerChoiceStrategies=C,exports.WorkerTypes=l,exports.availableParallelism=()=>{let e=1;try{e=h.availableParallelism()}catch{const t=h.cpus();Array.isArray(t)&&t.length>0&&(e=t.length)}return e};
|
package/lib/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{EventEmitter as e}from"node:events";import{Worker as t,MessageChannel as s,isMainThread as r,SHARE_ENV as i,parentPort as o,threadId as a}from"node:worker_threads";import n,{Worker as h}from"node:cluster";import{webcrypto as u,randomUUID as k}from"node:crypto";import{performance as d}from"node:perf_hooks";import{existsSync as c}from"node:fs";import*as l from"node:os";import{cpus as g}from"node:os";import{AsyncResource as m}from"node:async_hooks";const p=Object.freeze({fixed:"fixed",dynamic:"dynamic"});class w extends e{}const y=Object.freeze({ready:"ready",busy:"busy",full:"full",destroy:"destroy",error:"error",taskError:"taskError",backPressure:"backPressure"}),T=Object.freeze({thread:"thread",cluster:"cluster"}),f="default",W=Object.freeze((()=>{})),N={retries:6,runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},S={aggregate:!1,average:!1,median:!1},x=()=>{let e=1;try{e=l.availableParallelism()}catch{const t=l.cpus();Array.isArray(t)&&t.length>0&&(e=t.length)}return e},E=e=>e instanceof t?T.thread:e instanceof h?T.cluster:void 0,v=e=>e instanceof t?e.threadId:e instanceof h?e.id:void 0,I=e=>Array.isArray(e)&&0===e.length?0:Array.isArray(e)&&1===e.length?e[0]:e.reduce(((e,t)=>e+t),0)/e.length,C=e=>{if(Array.isArray(e)&&0===e.length)return 0;if(Array.isArray(e)&&1===e.length)return e[0];const t=e.slice().sort(((e,t)=>e-t));return(t[t.length-1>>1]+t[t.length>>1])/2},b=(e,t=2)=>{const s=Math.pow(10,t);return Math.round(e*s*(1+Number.EPSILON))/s},R=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),z=(e,t)=>t===e,O=e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name,Q=(e,t,s)=>{t.aggregate&&(e.aggregate=(e.aggregate??0)+s,e.minimum=K(s,e.minimum??1/0),e.maximum=P(s,e.maximum??-1/0),(t.average||t.median)&&null!=s&&(e.history.push(s),t.average?e.average=I(e.history):null!=e.average&&delete e.average,t.median?e.median=C(e.history):null!=e.median&&delete e.median))},F=()=>u.getRandomValues(new Uint32Array(1))[0]/4294967296,K=(...e)=>e.reduce(((e,t)=>e<t?e:t),1/0),P=(...e)=>e.reduce(((e,t)=>e>t?e:t),-1/0),M=Object.freeze({SOFT:"SOFT",HARD:"HARD"}),q=Object.freeze({ROUND_ROBIN:"ROUND_ROBIN",LEAST_USED:"LEAST_USED",LEAST_BUSY:"LEAST_BUSY",LEAST_ELU:"LEAST_ELU",FAIR_SHARE:"FAIR_SHARE",WEIGHTED_ROUND_ROBIN:"WEIGHTED_ROUND_ROBIN",INTERLEAVED_WEIGHTED_ROUND_ROBIN:"INTERLEAVED_WEIGHTED_ROUND_ROBIN"}),A=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"});class U{pool;opts;nextWorkerNodeKey=0;previousWorkerNodeKey=0;strategyPolicy={dynamicWorkerUsage:!1,dynamicWorkerReady:!0};taskStatisticsRequirements={runTime:S,waitTime:S,elu:S};constructor(e,t=N){this.pool=e,this.opts=t,this.opts={...N,...t},this.choose=this.choose.bind(this)}setTaskStatisticsRequirements(e){this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.runTime,e.runTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.waitTime,e.waitTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.elu,e.elu?.median)}toggleMedianMeasurementStatisticsRequirements(e,t){e.average&&t&&(e.average=!1,e.median=t),e.median&&!t&&(e.average=!0,e.median=t)}resetWorkerNodeKeyProperties(){this.nextWorkerNodeKey=0,this.previousWorkerNodeKey=0}setOptions(e){this.opts={...N,...e},this.setTaskStatisticsRequirements(this.opts)}isWorkerNodeReady(e){return this.pool.workerNodes[e].info.ready}hasWorkerNodeBackPressure(e){return this.pool.hasWorkerNodeBackPressure(e)}isWorkerNodeEligible(e){return this.isWorkerNodeReady(e)&&!this.hasWorkerNodeBackPressure(e)}getWorkerNodeTaskRunTime(e){return this.taskStatisticsRequirements.runTime.median?this.pool.workerNodes[e].usage.runTime.median??0:this.pool.workerNodes[e].usage.runTime.average??0}getWorkerNodeTaskWaitTime(e){return this.taskStatisticsRequirements.waitTime.median?this.pool.workerNodes[e].usage.waitTime.median??0:this.pool.workerNodes[e].usage.waitTime.average??0}getWorkerNodeTaskElu(e){return this.taskStatisticsRequirements.elu.median?this.pool.workerNodes[e].usage.elu.active.median??0:this.pool.workerNodes[e].usage.elu.active.average??0}setPreviousWorkerNodeKey(e){this.previousWorkerNodeKey=e??this.previousWorkerNodeKey}checkNextWorkerNodeEligibility(){this.isWorkerNodeEligible(this.nextWorkerNodeKey)||(this.nextWorkerNodeKey=void 0)}computeDefaultWorkerWeight(){let e=0;for(const t of g()){const s=t.speed.toString().length-1;e+=1/(t.speed/Math.pow(10,s))*Math.pow(10,s)}return Math.round(e/g().length)}}class B extends U{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:S,elu:{aggregate:!0,average:!0,median:!1}};constructor(e,t=N){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){for(const e of this.pool.workerNodes)delete e.strategyData?.virtualTaskEndTimestamp;return!0}update(e){return this.pool.workerNodes[e].strategyData={virtualTaskEndTimestamp:this.computeWorkerNodeVirtualTaskEndTimestamp(e)},!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.fairShareNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}fairShareNextWorkerNodeKey(){return this.pool.workerNodes.reduce(((e,t,s,r)=>(null==t.strategyData?.virtualTaskEndTimestamp&&(t.strategyData={virtualTaskEndTimestamp:this.computeWorkerNodeVirtualTaskEndTimestamp(s)}),t.strategyData.virtualTaskEndTimestamp<r[e].strategyData.virtualTaskEndTimestamp?s:e)),0)}computeWorkerNodeVirtualTaskEndTimestamp(e){return this.getWorkerNodeVirtualTaskEndTimestamp(e,this.getWorkerNodeVirtualTaskStartTimestamp(e))}getWorkerNodeVirtualTaskEndTimestamp(e,t){return t+(this.opts.measurement===A.elu?this.getWorkerNodeTaskElu(e):this.getWorkerNodeTaskRunTime(e))}getWorkerNodeVirtualTaskStartTimestamp(e){const t=this.pool.workerNodes[e]?.strategyData?.virtualTaskEndTimestamp,s=performance.now();return s<(t??-1/0)?t:s}}class D extends U{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:S,elu:S};roundId=0;defaultWorkerWeight;roundWeights;workerNodeId=0;workerNodeVirtualTaskRunTime=0;constructor(e,t=N){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight(),this.roundWeights=this.getRoundWeights()}reset(){return this.resetWorkerNodeKeyProperties(),this.roundId=0,this.workerNodeId=0,this.workerNodeVirtualTaskRunTime=0,!0}update(){return!0}choose(){for(let e=this.roundId;e<this.roundWeights.length;e++){this.roundId=e;for(let t=this.workerNodeId;t<this.pool.workerNodes.length;t++){this.workerNodeId=t,this.workerNodeId!==this.nextWorkerNodeKey&&0!==this.workerNodeVirtualTaskRunTime&&(this.workerNodeVirtualTaskRunTime=0);const s=this.opts.weights?.[t]??this.defaultWorkerWeight;if(s>=this.roundWeights[e]&&this.workerNodeVirtualTaskRunTime<s)return this.workerNodeVirtualTaskRunTime=this.workerNodeVirtualTaskRunTime+this.getWorkerNodeTaskRunTime(t),this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=t,this.nextWorkerNodeKey}}this.interleavedWeightedRoundRobinNextWorkerNodeId()}interleavedWeightedRoundRobinNextWorkerNodeId(){this.roundId===this.roundWeights.length-1&&this.workerNodeId===this.pool.workerNodes.length-1?(this.roundId=0,this.workerNodeId=0):this.workerNodeId===this.pool.workerNodes.length-1?(this.roundId=this.roundId+1,this.workerNodeId=0):this.workerNodeId=this.workerNodeId+1}remove(e){return 0===this.pool.workerNodes.length&&this.reset(),this.workerNodeId===e&&this.workerNodeId>this.pool.workerNodes.length-1&&(this.workerNodeId=this.pool.workerNodes.length-1),this.previousWorkerNodeKey===e&&this.previousWorkerNodeKey>this.pool.workerNodes.length-1&&(this.previousWorkerNodeKey=this.pool.workerNodes.length-1),!0}setOptions(e){super.setOptions(e),this.roundWeights=this.getRoundWeights()}getRoundWeights(){return null==this.opts.weights?[this.defaultWorkerWeight]:[...new Set(Object.values(this.opts.weights).slice().sort(((e,t)=>e-t)))]}}class L extends U{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:S};constructor(e,t=N){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastBusyNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastBusyNextWorkerNodeKey(){return this.pool.workerNodes.reduce(((e,t,s,r)=>(t.usage.runTime.aggregate??0)+(t.usage.waitTime.aggregate??0)<(r[e].usage.runTime.aggregate??0)+(r[e].usage.waitTime.aggregate??0)?s:e),0)}}class V extends U{constructor(e,t=N){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastUsedNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastUsedNextWorkerNodeKey(){return this.pool.workerNodes.reduce(((e,t,s,r)=>t.usage.tasks.executed+t.usage.tasks.executing+t.usage.tasks.queued<r[e].usage.tasks.executed+r[e].usage.tasks.executing+r[e].usage.tasks.queued?s:e),0)}}class _ extends U{taskStatisticsRequirements={runTime:S,waitTime:S,elu:{aggregate:!0,average:!1,median:!1}};constructor(e,t=N){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastEluNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastEluNextWorkerNodeKey(){return this.pool.workerNodes.reduce(((e,t,s,r)=>(t.usage.elu.active.aggregate??0)<(r[e].usage.elu.active.aggregate??0)?s:e),0)}}class j extends U{constructor(e,t=N){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.resetWorkerNodeKeyProperties(),!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;return this.setPreviousWorkerNodeKey(e),this.roundRobinNextWorkerNodeKey(),e}remove(e){return 0===this.pool.workerNodes.length&&this.reset(),this.nextWorkerNodeKey===e&&this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1),this.previousWorkerNodeKey===e&&this.previousWorkerNodeKey>this.pool.workerNodes.length-1&&(this.previousWorkerNodeKey=this.pool.workerNodes.length-1),!0}roundRobinNextWorkerNodeKey(){return this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,this.nextWorkerNodeKey}}class H extends U{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:S,elu:S};defaultWorkerWeight;workerNodeVirtualTaskRunTime=0;constructor(e,t=N){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight()}reset(){return this.resetWorkerNodeKeyProperties(),this.workerNodeVirtualTaskRunTime=0,!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.weightedRoundRobinNextWorkerNodeKey()}remove(e){return 0===this.pool.workerNodes.length&&this.reset(),this.nextWorkerNodeKey===e&&(this.workerNodeVirtualTaskRunTime=0,this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1)),this.previousWorkerNodeKey===e&&this.previousWorkerNodeKey>this.pool.workerNodes.length-1&&(this.previousWorkerNodeKey=this.pool.workerNodes.length-1),!0}weightedRoundRobinNextWorkerNodeKey(){const e=this.opts.weights?.[this.nextWorkerNodeKey??this.previousWorkerNodeKey]??this.defaultWorkerWeight;return this.workerNodeVirtualTaskRunTime<e?this.workerNodeVirtualTaskRunTime=this.workerNodeVirtualTaskRunTime+this.getWorkerNodeTaskRunTime(this.nextWorkerNodeKey??this.previousWorkerNodeKey):(this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,this.workerNodeVirtualTaskRunTime=0),this.nextWorkerNodeKey}}class ${workerChoiceStrategy;opts;workerChoiceStrategies;retriesCount=0;constructor(e,t=q.ROUND_ROBIN,s=N){this.workerChoiceStrategy=t,this.opts=s,this.opts={...N,...s},this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[q.ROUND_ROBIN,new(j.bind(this))(e,s)],[q.LEAST_USED,new(V.bind(this))(e,s)],[q.LEAST_BUSY,new(L.bind(this))(e,s)],[q.LEAST_ELU,new(_.bind(this))(e,s)],[q.FAIR_SHARE,new(B.bind(this))(e,s)],[q.WEIGHTED_ROUND_ROBIN,new(H.bind(this))(e,s)],[q.INTERLEAVED_WEIGHTED_ROUND_ROBIN,new(D.bind(this))(e,s)]])}getStrategyPolicy(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).strategyPolicy}getTaskStatisticsRequirements(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).taskStatisticsRequirements}setWorkerChoiceStrategy(e){this.workerChoiceStrategy!==e&&(this.workerChoiceStrategy=e),this.workerChoiceStrategies.get(this.workerChoiceStrategy)?.reset()}update(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).update(e)}execute(){const e=this.workerChoiceStrategies.get(this.workerChoiceStrategy).choose();if(null==e&&this.retriesCount<this.opts.retries)return this.retriesCount++,this.execute();if(null==e)throw new Error(`Worker node key chosen is null or undefined after ${this.retriesCount} retries`);return this.retriesCount=0,e}remove(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).remove(e)}setOptions(e){this.opts={...N,...e};for(const t of this.workerChoiceStrategies.values())t.setOptions(e)}}class G extends Array{size;constructor(e=1024,...t){super(),this.checkSize(e),this.size=e,arguments.length>1&&this.push(...t)}push(...e){const t=super.push(...e);return t>this.size&&super.splice(0,t-this.size),this.length}unshift(...e){return super.unshift(...e)>this.size&&super.splice(this.size,e.length),this.length}concat(...e){const t=super.concat(e);return t.size=this.size,t.length>t.size&&t.splice(0,t.length-t.size),t}splice(e,t,...s){let r=[];if(arguments.length>=3&&null!=t){if(r=super.splice(e,t,...s),this.length>this.size){const e=super.splice(0,this.length-this.size);r=new G(r.length+e.length,...r,...e)}}else r=2===arguments.length?super.splice(e,t):super.splice(e);return r}resize(e){if(this.checkSize(e),0===e)this.length=0;else if(e<this.size)for(let t=e;t<this.size;t++)super.pop();this.size=e}empty(){return 0===this.length}full(){return this.length===this.size}checkSize(e){if(!Number.isSafeInteger(e))throw new TypeError(`Invalid circular array size: ${e} is not a safe integer`);if(e<0)throw new RangeError(`Invalid circular array size: ${e} < 0`)}}class Y{data;next;prev;constructor(e){this.data=e}}class J{head;tail;size;maxSize;constructor(){this.clear()}push(e){const t=new Y(e);return null==this.tail?this.head=this.tail=t:(t.prev=this.tail,this.tail=this.tail.next=t),this.incrementSize()}unshift(e){const t=new Y(e);return null==this.head?this.head=this.tail=t:(t.next=this.head,this.head=this.head.prev=t),this.incrementSize()}pop(){if(null==this.head)return;const e=this.tail;return this.tail=this.tail.prev,null==this.tail?this.head=void 0:this.tail.next=void 0,--this.size,e?.data}shift(){if(null==this.head)return;const e=this.head;return this.head=this.head.next,null==this.head?this.tail=void 0:this.head.prev=void 0,--this.size,e?.data}peekFirst(){return this.head?.data}peekLast(){return this.tail?.data}clear(){this.head=void 0,this.tail=void 0,this.size=0,this.maxSize=0}[Symbol.iterator](){let e=this.head;return{next:()=>{if(null==e)return{value:void 0,done:!0};const t={value:e.data,done:!1};return e=e.next,t}}}backward(){return{[Symbol.iterator]:()=>{let e=this.tail;return{next:()=>{if(null==e)return{value:void 0,done:!0};const t={value:e.data,done:!1};return e=e.prev,t}}}}}incrementSize(){return++this.size,this.size>this.maxSize&&(this.maxSize=this.size),this.size}}class X{worker;info;usage;strategyData;messageChannel;tasksQueueBackPressureSize;onBackPressure;onEmptyQueue;tasksQueue;onBackPressureStarted;onEmptyQueueCount;taskFunctionsUsage;constructor(e,t){this.checkWorkerNodeArguments(e,t),this.worker=e,this.info=this.initWorkerInfo(e),this.usage=this.initWorkerUsage(),this.info.type===T.thread&&(this.messageChannel=new s),this.tasksQueueBackPressureSize=t,this.tasksQueue=new J,this.onBackPressureStarted=!1,this.onEmptyQueueCount=0,this.taskFunctionsUsage=new Map}tasksQueueSize(){return this.tasksQueue.size}enqueueTask(e){const t=this.tasksQueue.push(e);return null!=this.onBackPressure&&this.hasBackPressure()&&!this.onBackPressureStarted&&(this.onBackPressureStarted=!0,this.onBackPressure(this.info.id),this.onBackPressureStarted=!1),t}unshiftTask(e){const t=this.tasksQueue.unshift(e);return null!=this.onBackPressure&&this.hasBackPressure()&&!this.onBackPressureStarted&&(this.onBackPressureStarted=!0,this.onBackPressure(this.info.id),this.onBackPressureStarted=!1),t}dequeueTask(){const e=this.tasksQueue.shift();return null!=this.onEmptyQueue&&0===this.tasksQueue.size&&0===this.onEmptyQueueCount&&this.startOnEmptyQueue().catch(W),e}popTask(){const e=this.tasksQueue.pop();return null!=this.onEmptyQueue&&0===this.tasksQueue.size&&0===this.onEmptyQueueCount&&this.startOnEmptyQueue().catch(W),e}clearTasksQueue(){this.tasksQueue.clear()}hasBackPressure(){return this.tasksQueue.size>=this.tasksQueueBackPressureSize}resetUsage(){this.usage=this.initWorkerUsage(),this.taskFunctionsUsage.clear()}closeChannel(){null!=this.messageChannel&&(this.messageChannel?.port1.unref(),this.messageChannel?.port2.unref(),this.messageChannel?.port1.close(),this.messageChannel?.port2.close(),delete this.messageChannel)}getTaskFunctionWorkerUsage(e){if(!Array.isArray(this.info.taskFunctions))throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function names list is not yet defined`);if(Array.isArray(this.info.taskFunctions)&&this.info.taskFunctions.length<3)throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function names list has less than 3 elements`);return e===f&&(e=this.info.taskFunctions[1]),this.taskFunctionsUsage.has(e)||this.taskFunctionsUsage.set(e,this.initTaskFunctionWorkerUsage(e)),this.taskFunctionsUsage.get(e)}async startOnEmptyQueue(){this.onEmptyQueueCount>0&&(this.usage.tasks.executing>0||this.tasksQueue.size>0)?this.onEmptyQueueCount=0:(++this.onEmptyQueueCount,this.onEmptyQueue?.(this.info.id),await(async e=>{await new Promise((t=>{setTimeout(t,e)}))})(((e=0,t=100)=>{const s=Math.pow(2,e)*t;return s+.2*s*F()})(this.onEmptyQueueCount)),await this.startOnEmptyQueue())}initWorkerInfo(e){return{id:v(e),type:E(e),dynamic:!1,ready:!1}}initWorkerUsage(){const e=()=>this.tasksQueue.size,t=()=>this.tasksQueue.maxSize;return{tasks:{executed:0,executing:0,get queued(){return e()},get maxQueued(){return t()},stolen:0,failed:0},runTime:{history:new G},waitTime:{history:new G},elu:{idle:{history:new G},active:{history:new G}}}}initTaskFunctionWorkerUsage(e){const t=()=>{let t=0;for(const s of this.tasksQueue)(s.name===f&&e===this.info.taskFunctions[1]||s.name!==f&&e===s.name)&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},stolen:0,failed:0},runTime:{history:new G},waitTime:{history:new G},elu:{idle:{history:new G},active:{history:new G}}}}checkWorkerNodeArguments(e,t){if(null==e)throw new TypeError("Cannot construct a worker node without a worker");if(null==t)throw new TypeError("Cannot construct a worker node without a tasks queue back pressure size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot construct a worker node with a tasks queue back pressure size that is not an integer");if(t<=0)throw new RangeError("Cannot construct a worker node with a tasks queue back pressure size that is not a positive integer")}}class Z{numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;max;started;starting;startTimestamp;constructor(e,t,s){if(this.numberOfWorkers=e,this.filePath=t,this.opts=s,!this.isMain())throw new Error("Cannot start a pool from a worker with the same type as the pool");this.checkNumberOfWorkers(this.numberOfWorkers),this.checkFilePath(this.filePath),this.checkPoolOptions(this.opts),this.chooseWorkerNode=this.chooseWorkerNode.bind(this),this.executeTask=this.executeTask.bind(this),this.enqueueTask=this.enqueueTask.bind(this),!0===this.opts.enableEvents&&(this.emitter=new w),this.workerChoiceStrategyContext=new $(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook(),this.started=!1,this.starting=!1,!0===this.opts.startWorkers&&this.start(),this.startTimestamp=d.now()}checkFilePath(e){if(null==e||"string"!=typeof e||"string"==typeof e&&0===e.trim().length)throw new Error("Please specify a file with a worker implementation");if(!c(e))throw new Error(`Cannot find the worker file '${e}'`)}checkNumberOfWorkers(e){if(null==e)throw new Error("Cannot instantiate a pool without specifying the number of workers");if(!Number.isSafeInteger(e))throw new TypeError("Cannot instantiate a pool with a non safe integer number of workers");if(e<0)throw new RangeError("Cannot instantiate a pool with a negative number of workers");if(this.type===p.fixed&&0===e)throw new RangeError("Cannot instantiate a fixed pool with zero worker")}checkDynamicPoolSize(e,t){if(this.type===p.dynamic){if(null==t)throw new TypeError("Cannot instantiate a dynamic pool without specifying the maximum pool size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot instantiate a dynamic pool with a non safe integer maximum pool size");if(e>t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size");if(0===t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size equal to zero");if(e===t)throw new RangeError("Cannot instantiate a dynamic pool with a minimum pool size equal to the maximum pool size. Use a fixed pool instead")}}checkPoolOptions(e){if(!R(e))throw new TypeError("Invalid pool options: must be a plain object");this.opts.startWorkers=e.startWorkers??!0,this.opts.workerChoiceStrategy=e.workerChoiceStrategy??q.ROUND_ROBIN,this.checkValidWorkerChoiceStrategy(this.opts.workerChoiceStrategy),this.opts.workerChoiceStrategyOptions={...N,...e.workerChoiceStrategyOptions},this.checkValidWorkerChoiceStrategyOptions(this.opts.workerChoiceStrategyOptions),this.opts.restartWorkerOnError=e.restartWorkerOnError??!0,this.opts.enableEvents=e.enableEvents??!0,this.opts.enableTasksQueue=e.enableTasksQueue??!1,this.opts.enableTasksQueue&&(this.checkValidTasksQueueOptions(e.tasksQueueOptions),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e.tasksQueueOptions))}checkValidWorkerChoiceStrategy(e){if(!Object.values(q).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)}checkValidWorkerChoiceStrategyOptions(e){if(!R(e))throw new TypeError("Invalid worker choice strategy options: must be a plain object");if(null!=e.retries&&!Number.isSafeInteger(e.retries))throw new TypeError("Invalid worker choice strategy options: retries must be an integer");if(null!=e.retries&&e.retries<0)throw new RangeError(`Invalid worker choice strategy options: retries '${e.retries}' must be greater or equal than zero`);if(null!=e.weights&&Object.keys(e.weights).length!==this.maxSize)throw new Error("Invalid worker choice strategy options: must have a weight for each worker node");if(null!=e.measurement&&!Object.values(A).includes(e.measurement))throw new Error(`Invalid worker choice strategy options: invalid measurement '${e.measurement}'`)}checkValidTasksQueueOptions(e){if(null!=e&&!R(e))throw new TypeError("Invalid tasks queue options: must be a plain object");if(null!=e?.concurrency&&!Number.isSafeInteger(e?.concurrency))throw new TypeError("Invalid worker node tasks concurrency: must be an integer");if(null!=e?.concurrency&&e?.concurrency<=0)throw new RangeError(`Invalid worker node tasks concurrency: ${e?.concurrency} is a negative integer or zero`);if(null!=e?.size&&!Number.isSafeInteger(e?.size))throw new TypeError("Invalid worker node tasks queue size: must be an integer");if(null!=e?.size&&e?.size<=0)throw new RangeError(`Invalid worker node tasks queue size: ${e?.size} is a negative integer or zero`)}get info(){return{version:"2.6.45",type:this.type,worker:this.worker,started:this.started,ready:this.ready,strategy:this.opts.workerChoiceStrategy,minSize:this.minSize,maxSize:this.maxSize,...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{utilization:b(this.utilization)},workerNodes:this.workerNodes.length,idleWorkerNodes:this.workerNodes.reduce(((e,t)=>0===t.usage.tasks.executing?e+1:e),0),busyWorkerNodes:this.workerNodes.reduce(((e,t)=>t.usage.tasks.executing>0?e+1:e),0),executedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executed),0),executingTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executing),0),...!0===this.opts.enableTasksQueue&&{queuedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.queued),0)},...!0===this.opts.enableTasksQueue&&{maxQueuedTasks:this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.maxQueued??0)),0)},...!0===this.opts.enableTasksQueue&&{backPressure:this.hasBackPressure()},...!0===this.opts.enableTasksQueue&&{stolenTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.stolen),0)},failedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.failed),0),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&{runTime:{minimum:b(K(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:b(P(...this.workerNodes.map((e=>e.usage.runTime?.maximum??-1/0)))),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.average&&{average:b(I(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&{median:b(C(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:b(K(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:b(P(...this.workerNodes.map((e=>e.usage.waitTime?.maximum??-1/0)))),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.average&&{average:b(I(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.waitTime.history)),[])))},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&{median:b(C(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.waitTime.history)),[])))}}}}}get ready(){return this.workerNodes.reduce(((e,t)=>!t.info.dynamic&&t.info.ready?e+1:e),0)>=this.minSize}get utilization(){const e=(d.now()-this.startTimestamp)*this.maxSize;return(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)+this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0))/e}get minSize(){return this.numberOfWorkers}get maxSize(){return this.max??this.numberOfWorkers}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Worker message received without worker id");if(null!=e.workerId&&-1===this.getWorkerNodeKeyByWorkerId(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKeyByWorker(e){return this.workerNodes.findIndex((t=>t.worker===e))}getWorkerNodeKeyByWorkerId(e){return this.workerNodes.findIndex((t=>t.info.id===e))}setWorkerChoiceStrategy(e,t){this.checkValidWorkerChoiceStrategy(e),this.opts.workerChoiceStrategy=e,this.workerChoiceStrategyContext.setWorkerChoiceStrategy(this.opts.workerChoiceStrategy),null!=t&&this.setWorkerChoiceStrategyOptions(t);for(const[e,t]of this.workerNodes.entries())t.resetUsage(),this.sendStatisticsMessageToWorker(e)}setWorkerChoiceStrategyOptions(e){this.checkValidWorkerChoiceStrategyOptions(e),this.opts.workerChoiceStrategyOptions={...N,...e},this.workerChoiceStrategyContext.setOptions(this.opts.workerChoiceStrategyOptions)}enableTasksQueue(e,t){!0!==this.opts.enableTasksQueue||e||this.flushTasksQueues(),this.opts.enableTasksQueue=e,this.setTasksQueueOptions(t)}setTasksQueueOptions(e){!0===this.opts.enableTasksQueue?(this.checkValidTasksQueueOptions(e),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e),this.setTasksQueueSize(this.opts.tasksQueueOptions.size)):null!=this.opts.tasksQueueOptions&&delete this.opts.tasksQueueOptions}setTasksQueueSize(e){for(const t of this.workerNodes)t.tasksQueueBackPressureSize=e}buildTasksQueueOptions(e){return{size:Math.pow(this.maxSize,2),concurrency:1,taskStealing:!0,tasksStealingOnBackPressure:!0,...e}}get full(){return this.workerNodes.length>=this.maxSize}internalBusy(){return!0===this.opts.enableTasksQueue?-1===this.workerNodes.findIndex((e=>e.info.ready&&e.usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency)):-1===this.workerNodes.findIndex((e=>e.info.ready&&0===e.usage.tasks.executing))}listTaskFunctions(){for(const e of this.workerNodes)if(Array.isArray(e.info.taskFunctions)&&e.info.taskFunctions.length>0)return e.info.taskFunctions;return[]}shallExecuteTask(e){return 0===this.tasksQueueSize(e)&&this.workerNodes[e].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency}async execute(e,t,s){return await new Promise(((r,i)=>{if(!this.started)return void i(new Error("Cannot execute a task on not started pool"));if(null!=t&&"string"!=typeof t)return void i(new TypeError("name argument must be a string"));if(null!=t&&"string"==typeof t&&0===t.trim().length)return void i(new TypeError("name argument must not be an empty string"));if(null!=s&&!Array.isArray(s))return void i(new TypeError("transferList argument must be an array"));const o=d.now(),a=this.chooseWorkerNode(),n={name:t??f,data:e??{},transferList:s,timestamp:o,workerId:this.getWorkerInfo(a).id,taskId:k()};this.promiseResponseMap.set(n.taskId,{resolve:r,reject:i,workerNodeKey:a}),!1===this.opts.enableTasksQueue||!0===this.opts.enableTasksQueue&&this.shallExecuteTask(a)?this.executeTask(a,n):this.enqueueTask(a,n)}))}start(){for(this.starting=!0;this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.numberOfWorkers;)this.createAndSetupWorkerNode();this.starting=!1,this.started=!0}async destroy(){await Promise.all(this.workerNodes.map((async(e,t)=>{await this.destroyWorkerNode(t)}))),this.emitter?.emit(y.destroy,this.info),this.started=!1}async sendKillMessageToWorker(e,t){await new Promise(((s,r)=>{this.registerWorkerMessageListener(e,(e=>{"success"===e.kill?s():"failure"===e.kill&&r(new Error(`Worker ${t} kill message handling failed`))})),this.sendToWorker(e,{kill:!0,workerId:t})}))}setupHook(){}beforeTaskExecutionHook(e,t){if(null!=this.workerNodes[e]?.usage){const s=this.workerNodes[e].usage;++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t)}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name)){const s=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name);++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t)}}afterTaskExecutionHook(e,t){if(null!=this.workerNodes[e]?.usage){const s=this.workerNodes[e].usage;this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t)}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance?.name)){const s=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance?.name);this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t)}}shallUpdateTaskFunctionWorkerUsage(e){const t=this.getWorkerInfo(e);return null!=t&&Array.isArray(t.taskFunctions)&&t.taskFunctions.length>2}updateTaskStatisticsWorkerUsage(e,t){const s=e.tasks;null!=s.executing&&s.executing>0&&--s.executing,null==t.taskError?++s.executed:++s.failed}updateRunTimeWorkerUsage(e,t){null==t.taskError&&Q(e.runTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime,t.taskPerformance?.runTime??0)}updateWaitTimeWorkerUsage(e,t){const s=d.now(),r=s-(t.timestamp??s);Q(e.waitTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime,r)}updateEluWorkerUsage(e,t){if(null!=t.taskError)return;const s=this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu;Q(e.elu.active,s,t.taskPerformance?.elu?.active??0),Q(e.elu.idle,s,t.taskPerformance?.elu?.idle??0),s.aggregate&&null!=t.taskPerformance?.elu&&(null!=e.elu.utilization?e.elu.utilization=(e.elu.utilization+t.taskPerformance.elu.utilization)/2:e.elu.utilization=t.taskPerformance.elu.utilization)}chooseWorkerNode(){if(this.shallCreateDynamicWorker()){const e=this.createAndSetupDynamicWorkerNode();if(this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerUsage)return e}return this.workerChoiceStrategyContext.execute()}shallCreateDynamicWorker(){return this.type===p.dynamic&&!this.full&&this.internalBusy()}createAndSetupWorkerNode(){const e=this.createWorker();e.on("online",this.opts.onlineHandler??W),e.on("message",this.opts.messageHandler??W),e.on("error",this.opts.errorHandler??W),e.on("error",(t=>{const s=this.getWorkerNodeKeyByWorker(e),r=this.getWorkerInfo(s);r.ready=!1,this.workerNodes[s].closeChannel(),this.emitter?.emit(y.error,t),!0===this.opts.restartWorkerOnError&&this.started&&!this.starting&&(r.dynamic?this.createAndSetupDynamicWorkerNode():this.createAndSetupWorkerNode()),!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(s)})),e.on("exit",this.opts.exitHandler??W),e.once("exit",(()=>{this.removeWorkerNode(e)}));const t=this.addWorkerNode(e);return this.afterWorkerNodeSetup(t),t}createAndSetupDynamicWorkerNode(){const e=this.createAndSetupWorkerNode();this.registerWorkerMessageListener(e,(e=>{const t=this.getWorkerNodeKeyByWorkerId(e.workerId),s=this.workerNodes[t].usage;(z(M.HARD,e.kill)||z(M.SOFT,e.kill)&&(!1===this.opts.enableTasksQueue&&0===s.tasks.executing||!0===this.opts.enableTasksQueue&&0===s.tasks.executing&&0===this.tasksQueueSize(t)))&&this.destroyWorkerNode(t).catch((e=>{this.emitter?.emit(y.error,e)}))}));const t=this.getWorkerInfo(e);return this.sendToWorker(e,{checkActive:!0,workerId:t.id}),t.dynamic=!0,(this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerReady||this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerUsage)&&(t.ready=!0),this.checkAndEmitDynamicWorkerCreationEvents(),e}afterWorkerNodeSetup(e){this.registerWorkerMessageListener(e,this.workerListener()),this.sendStartupMessageToWorker(e),this.sendStatisticsMessageToWorker(e),!0===this.opts.enableTasksQueue&&(!0===this.opts.tasksQueueOptions?.taskStealing&&(this.workerNodes[e].onEmptyQueue=this.taskStealingOnEmptyQueue.bind(this)),!0===this.opts.tasksQueueOptions?.tasksStealingOnBackPressure&&(this.workerNodes[e].onBackPressure=this.tasksStealingOnBackPressure.bind(this)))}sendStatisticsMessageToWorker(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate},workerId:this.getWorkerInfo(e).id})}redistributeQueuedTasks(e){for(;this.tasksQueueSize(e)>0;){const t=this.workerNodes.reduce(((e,t,s,r)=>t.info.ready&&t.usage.tasks.queued<r[e].usage.tasks.queued?s:e),0),s=this.workerNodes[t],r={...this.dequeueTask(e),workerId:s.info.id};this.shallExecuteTask(t)?this.executeTask(t,r):this.enqueueTask(t,r)}}updateTaskStolenStatisticsWorkerUsage(e,t){const s=this.workerNodes[e];if(null!=s?.usage&&++s.usage.tasks.stolen,this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=s.getTaskFunctionWorkerUsage(t)){++s.getTaskFunctionWorkerUsage(t).tasks.stolen}}taskStealingOnEmptyQueue(e){const t=this.getWorkerNodeKeyByWorkerId(e),s=this.workerNodes[t],r=this.workerNodes.slice().sort(((e,t)=>t.usage.tasks.queued-e.usage.tasks.queued)).find((t=>t.info.ready&&t.info.id!==e&&t.usage.tasks.queued>0));if(null!=r){const e={...r.popTask(),workerId:s.info.id};this.shallExecuteTask(t)?this.executeTask(t,e):this.enqueueTask(t,e),this.updateTaskStolenStatisticsWorkerUsage(t,e.name)}}tasksStealingOnBackPressure(e){if(this.opts.tasksQueueOptions?.size<=1)return;const t=this.workerNodes[this.getWorkerNodeKeyByWorkerId(e)],s=this.workerNodes.slice().sort(((e,t)=>e.usage.tasks.queued-t.usage.tasks.queued));for(const[r,i]of s.entries())if(t.usage.tasks.queued>0&&i.info.ready&&i.info.id!==e&&i.usage.tasks.queued<this.opts.tasksQueueOptions?.size-1){const e={...t.popTask(),workerId:i.info.id};this.shallExecuteTask(r)?this.executeTask(r,e):this.enqueueTask(r,e),this.updateTaskStolenStatisticsWorkerUsage(r,e.name)}}workerListener(){return e=>{this.checkMessageWorkerId(e),null!=e.ready&&null!=e.taskFunctions?this.handleWorkerReadyResponse(e):null!=e.taskId?this.handleTaskExecutionResponse(e):null!=e.taskFunctions&&(this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId)).taskFunctions=e.taskFunctions)}}handleWorkerReadyResponse(e){if(!1===e.ready)throw new Error(`Worker ${e.workerId} failed to initialize`);const t=this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId));t.ready=e.ready,t.taskFunctions=e.taskFunctions,null!=this.emitter&&this.ready&&this.emitter.emit(y.ready,this.info)}handleTaskExecutionResponse(e){const{taskId:t,taskError:s,data:r}=e,i=this.promiseResponseMap.get(t);if(null!=i){null!=s?(this.emitter?.emit(y.taskError,s),i.reject(s.message)):i.resolve(r);const o=i.workerNodeKey;this.afterTaskExecutionHook(o,e),this.workerChoiceStrategyContext.update(o),this.promiseResponseMap.delete(t),!0===this.opts.enableTasksQueue&&this.tasksQueueSize(o)>0&&this.workerNodes[o].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&this.executeTask(o,this.dequeueTask(o))}}checkAndEmitTaskExecutionEvents(){this.busy&&this.emitter?.emit(y.busy,this.info)}checkAndEmitTaskQueuingEvents(){this.hasBackPressure()&&this.emitter?.emit(y.backPressure,this.info)}checkAndEmitDynamicWorkerCreationEvents(){this.type===p.dynamic&&this.full&&this.emitter?.emit(y.full,this.info)}getWorkerInfo(e){return this.workerNodes[e].info}addWorkerNode(e){const t=new X(e,this.opts.tasksQueueOptions?.size??Math.pow(this.maxSize,2));this.starting&&(t.info.ready=!0),this.workerNodes.push(t);const s=this.getWorkerNodeKeyByWorker(e);if(-1===s)throw new Error("Worker added not found in worker nodes");return s}removeWorkerNode(e){const t=this.getWorkerNodeKeyByWorker(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategyContext.remove(t))}hasWorkerNodeBackPressure(e){return!0===this.opts.enableTasksQueue&&this.workerNodes[e].hasBackPressure()}hasBackPressure(){return!0===this.opts.enableTasksQueue&&-1===this.workerNodes.findIndex((e=>!e.hasBackPressure()))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(e,t,t.transferList),this.checkAndEmitTaskExecutionEvents()}enqueueTask(e,t){const s=this.workerNodes[e].enqueueTask(t);return this.checkAndEmitTaskQueuingEvents(),s}dequeueTask(e){return this.workerNodes[e].dequeueTask()}tasksQueueSize(e){return this.workerNodes[e].tasksQueueSize()}flushTasksQueue(e){for(;this.tasksQueueSize(e)>0;)this.executeTask(e,this.dequeueTask(e));this.workerNodes[e].clearTasksQueue()}flushTasksQueues(){for(const[e]of this.workerNodes.entries())this.flushTasksQueue(e)}}class ee extends Z{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}setupHook(){n.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return n.isPrimary}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e],s=t.worker,r=new Promise((e=>{s.on("exit",(()=>{e()}))}));s.on("disconnect",(()=>{s.kill()})),await this.sendKillMessageToWorker(e,t.info.id),s.disconnect(),await r}sendToWorker(e,t){this.workerNodes[e].worker.send(t)}sendStartupMessageToWorker(e){this.sendToWorker(e,{ready:!1,workerId:this.workerNodes[e].info.id})}registerWorkerMessageListener(e,t){this.workerNodes[e].worker.on("message",t)}createWorker(){return n.fork(this.opts.env)}get type(){return p.fixed}get worker(){return T.cluster}get busy(){return this.internalBusy()}}class te extends ee{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return p.dynamic}get busy(){return this.full&&this.internalBusy()}}class se extends Z{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}isMain(){return r}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e],s=t.worker,r=new Promise((e=>{s.on("exit",(()=>{e()}))}));await this.sendKillMessageToWorker(e,t.info.id),t.closeChannel(),await s.terminate(),await r}sendToWorker(e,t,s){this.workerNodes[e].messageChannel.port1.postMessage(t,s)}sendStartupMessageToWorker(e){const t=this.workerNodes[e],s=t.worker,r=t.messageChannel.port2;s.postMessage({ready:!1,workerId:t.info.id,port:r},[r])}registerWorkerMessageListener(e,t){this.workerNodes[e].messageChannel.port1.on("message",t)}createWorker(){return new t(this.filePath,{env:i,...this.opts.workerOptions})}get type(){return p.fixed}get worker(){return T.thread}get busy(){return this.internalBusy()}}class re extends se{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return p.dynamic}get busy(){return this.full&&this.internalBusy()}}const ie=6e4,oe={killBehavior:M.SOFT,maxInactiveTime:ie,killHandler:W};class ae extends m{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,s,r,i=oe){if(super(e),this.isMain=t,this.mainWorker=s,this.opts=i,null==this.isMain)throw new Error("isMain parameter is mandatory");this.checkTaskFunctions(r),this.checkWorkerOptions(this.opts),this.isMain||this.getMainWorker().on("message",this.handleReadyMessage.bind(this))}checkWorkerOptions(e){this.opts={...oe,...e},delete this.opts.async}checkValidTaskFunction(e,t){if("string"!=typeof e)throw new TypeError("A taskFunctions parameter object key is not a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("A taskFunctions parameter object key is an empty string");if("function"!=typeof t)throw new TypeError("A taskFunctions parameter object value is not a function")}checkTaskFunctions(e){if(null==e)throw new Error("taskFunctions parameter is mandatory");if(this.taskFunctions=new Map,"function"==typeof e){const t=e.bind(this);this.taskFunctions.set(f,t),this.taskFunctions.set("string"==typeof e.name&&e.name.trim().length>0?e.name:"fn1",t)}else{if(!R(e))throw new TypeError("taskFunctions parameter is not a function or a plain object");{let t=!0;for(const[s,r]of Object.entries(e)){this.checkValidTaskFunction(s,r);const e=r.bind(this);t&&(this.taskFunctions.set(f,e),t=!1),this.taskFunctions.set(s,e)}if(t)throw new Error("taskFunctions parameter object is empty")}}}hasTaskFunction(e){return this.checkTaskFunctionName(e),this.taskFunctions.has(e)}addTaskFunction(e,t){if(this.checkTaskFunctionName(e),e===f)throw new Error("Cannot add a task function with the default reserved name");if("function"!=typeof t)throw new TypeError("fn parameter is not a function");try{const s=t.bind(this);return this.taskFunctions.get(e)===this.taskFunctions.get(f)&&this.taskFunctions.set(f,s),this.taskFunctions.set(e,s),this.sendTaskFunctionsListToMainWorker(),!0}catch{return!1}}removeTaskFunction(e){if(this.checkTaskFunctionName(e),e===f)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(f))throw new Error("Cannot remove the task function used as the default task function");const t=this.taskFunctions.delete(e);return this.sendTaskFunctionsListToMainWorker(),t}listTaskFunctions(){const e=[...this.taskFunctions.keys()];let t=f;for(const[e,s]of this.taskFunctions)if(e!==f&&s===this.taskFunctions.get(f)){t=e;break}return[e[e.indexOf(f)],t,...e.filter((e=>e!==f&&e!==t))]}setDefaultTaskFunction(e){if(this.checkTaskFunctionName(e),e===f)throw new Error("Cannot set the default task function reserved name as the default task function");if(!this.taskFunctions.has(e))throw new Error("Cannot set the default task function to a non-existing task function");try{return this.taskFunctions.set(f,this.taskFunctions.get(e)),!0}catch{return!1}}checkTaskFunctionName(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("name parameter is an empty string")}messageListener(e){this.checkMessageWorkerId(e),null!=e.statistics?this.statistics=e.statistics:null!=e.checkActive?e.checkActive?this.startCheckActive():this.stopCheckActive():null!=e.taskId&&null!=e.data?this.run(e):!0===e.kill&&this.handleKillMessage(e)}handleKillMessage(e){if(this.stopCheckActive(),O(this.opts.killHandler))(this.opts.killHandler?.()).then((()=>(this.sendToMainWorker({kill:"success",workerId:this.id}),null))).catch((()=>{this.sendToMainWorker({kill:"failure",workerId:this.id})})).finally((()=>{this.emitDestroy()})).catch(W);else try{this.opts.killHandler?.(),this.sendToMainWorker({kill:"success",workerId:this.id})}catch{this.sendToMainWorker({kill:"failure",workerId:this.id})}finally{this.emitDestroy()}}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Message worker id is not set");if(null!=e.workerId&&e.workerId!==this.id)throw new Error(`Message worker id ${e.workerId} does not match the worker id ${this.id}`)}startCheckActive(){this.lastTaskTimestamp=d.now(),this.activeInterval=setInterval(this.checkActive.bind(this),(this.opts.maxInactiveTime??ie)/2)}stopCheckActive(){null!=this.activeInterval&&(clearInterval(this.activeInterval),delete this.activeInterval)}checkActive(){d.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??ie)&&this.sendToMainWorker({kill:this.opts.killBehavior,workerId:this.id})}getMainWorker(){if(null==this.mainWorker)throw new Error("Main worker not set");return this.mainWorker}sendTaskFunctionsListToMainWorker(){this.sendToMainWorker({taskFunctions:this.listTaskFunctions(),workerId:this.id})}handleError(e){return e instanceof Error?e.message:e}run(e){const{name:t,taskId:s,data:r}=e,i=this.taskFunctions.get(t??f);null!=i?O(i)?this.runInAsyncScope(this.runAsync.bind(this),this,i,e):this.runInAsyncScope(this.runSync.bind(this),this,i,e):this.sendToMainWorker({taskError:{name:t,message:`Task function '${t}' not found`,data:r},workerId:this.id,taskId:s})}runSync(e,t){const{name:s,taskId:r,data:i}=t;try{let t=this.beginTaskPerformance(s);const o=e(i);t=this.endTaskPerformance(t),this.sendToMainWorker({data:o,taskPerformance:t,workerId:this.id,taskId:r})}catch(e){this.sendToMainWorker({taskError:{name:s,message:this.handleError(e),data:i},workerId:this.id,taskId:r})}finally{this.updateLastTaskTimestamp()}}runAsync(e,t){const{name:s,taskId:r,data:i}=t;let o=this.beginTaskPerformance(s);e(i).then((e=>(o=this.endTaskPerformance(o),this.sendToMainWorker({data:e,taskPerformance:o,workerId:this.id,taskId:r}),null))).catch((e=>{this.sendToMainWorker({taskError:{name:s,message:this.handleError(e),data:i},workerId:this.id,taskId:r})})).finally((()=>{this.updateLastTaskTimestamp()})).catch(W)}beginTaskPerformance(e){return this.checkStatistics(),{name:e??f,timestamp:d.now(),...this.statistics.elu&&{elu:d.eventLoopUtilization()}}}endTaskPerformance(e){return this.checkStatistics(),{...e,...this.statistics.runTime&&{runTime:d.now()-e.timestamp},...this.statistics.elu&&{elu:d.eventLoopUtilization(e.elu)}}}checkStatistics(){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set")}updateLastTaskTimestamp(){null!=this.activeInterval&&(this.lastTaskTimestamp=d.now())}}class ne extends ae{constructor(e,t={}){super("worker-cluster-pool:poolifier",n.isPrimary,n.worker,e,t)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready)try{this.getMainWorker().on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctions:this.listTaskFunctions(),workerId:this.id})}catch{this.sendToMainWorker({ready:!1,taskFunctions:this.listTaskFunctions(),workerId:this.id})}}get id(){return this.getMainWorker().id}sendToMainWorker(e){this.getMainWorker().send(e)}}class he extends ae{port;constructor(e,t={}){super("worker-thread-pool:poolifier",r,o,e,t)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready&&null!=e.port)try{this.port=e.port,this.port.on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctions:this.listTaskFunctions(),workerId:this.id})}catch{this.sendToMainWorker({ready:!1,taskFunctions:this.listTaskFunctions(),workerId:this.id})}}handleKillMessage(e){super.handleKillMessage(e),this.port?.unref(),this.port?.close()}get id(){return a}sendToMainWorker(e){this.port.postMessage(e)}handleError(e){return e}}export{ne as ClusterWorker,te as DynamicClusterPool,re as DynamicThreadPool,ee as FixedClusterPool,se as FixedThreadPool,M as KillBehaviors,A as Measurements,y as PoolEvents,p as PoolTypes,he as ThreadWorker,q as WorkerChoiceStrategies,T as WorkerTypes,x as availableParallelism};
|
|
1
|
+
import{EventEmitter as e}from"node:events";import{Worker as t,MessageChannel as s,isMainThread as r,SHARE_ENV as i,parentPort as o,threadId as n}from"node:worker_threads";import{existsSync as a}from"node:fs";import*as u from"node:os";import{cpus as h}from"node:os";import{webcrypto as k,randomUUID as c}from"node:crypto";import d,{Worker as l}from"node:cluster";import{performance as g}from"node:perf_hooks";import{AsyncResource as m}from"node:async_hooks";const p=Object.freeze({fixed:"fixed",dynamic:"dynamic"});class w extends e{}const y=Object.freeze({ready:"ready",busy:"busy",full:"full",destroy:"destroy",error:"error",taskError:"taskError",backPressure:"backPressure"}),T=Object.freeze({thread:"thread",cluster:"cluster"}),f="default",N=Object.freeze((()=>{})),W={retries:6,runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},S={aggregate:!1,average:!1,median:!1},x=()=>{let e=1;try{e=u.availableParallelism()}catch{const t=u.cpus();Array.isArray(t)&&t.length>0&&(e=t.length)}return e},E=e=>e instanceof t?T.thread:e instanceof l?T.cluster:void 0,v=e=>e instanceof t?e.threadId:e instanceof l?e.id:void 0,I=e=>Array.isArray(e)&&0===e.length?0:Array.isArray(e)&&1===e.length?e[0]:e.reduce(((e,t)=>e+t),0)/e.length,b=e=>{if(Array.isArray(e)&&0===e.length)return 0;if(Array.isArray(e)&&1===e.length)return e[0];const t=e.slice().sort(((e,t)=>e-t));return(t[t.length-1>>1]+t[t.length>>1])/2},F=(e,t=2)=>{const s=Math.pow(10,t);return Math.round(e*s*(1+Number.EPSILON))/s},C=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),O=(e,t)=>t===e,R=e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name,z=()=>k.getRandomValues(new Uint32Array(1))[0]/4294967296,Q=(...e)=>e.reduce(((e,t)=>e<t?e:t),1/0),M=(...e)=>e.reduce(((e,t)=>e>t?e:t),-1/0),P=Object.freeze({ROUND_ROBIN:"ROUND_ROBIN",LEAST_USED:"LEAST_USED",LEAST_BUSY:"LEAST_BUSY",LEAST_ELU:"LEAST_ELU",FAIR_SHARE:"FAIR_SHARE",WEIGHTED_ROUND_ROBIN:"WEIGHTED_ROUND_ROBIN",INTERLEAVED_WEIGHTED_ROUND_ROBIN:"INTERLEAVED_WEIGHTED_ROUND_ROBIN"}),K=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"}),B=(e,t)=>{if(null==t)throw new TypeError("Cannot instantiate a dynamic pool without specifying the maximum pool size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot instantiate a dynamic pool with a non safe integer maximum pool size");if(e>t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size");if(0===t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size equal to zero");if(e===t)throw new RangeError("Cannot instantiate a dynamic pool with a minimum pool size equal to the maximum pool size. Use a fixed pool instead")},q=e=>{if(null!=e&&!Object.values(P).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)},U=e=>{if(null!=e&&!C(e))throw new TypeError("Invalid tasks queue options: must be a plain object");if(null!=e?.concurrency&&!Number.isSafeInteger(e.concurrency))throw new TypeError("Invalid worker node tasks concurrency: must be an integer");if(null!=e?.concurrency&&e.concurrency<=0)throw new RangeError(`Invalid worker node tasks concurrency: ${e.concurrency} is a negative integer or zero`);if(null!=e?.size&&!Number.isSafeInteger(e.size))throw new TypeError("Invalid worker node tasks queue size: must be an integer");if(null!=e?.size&&e.size<=0)throw new RangeError(`Invalid worker node tasks queue size: ${e.size} is a negative integer or zero`)},A=(e,t,s)=>{t.aggregate&&(e.aggregate=(e.aggregate??0)+s,e.minimum=Q(s,e.minimum??1/0),e.maximum=M(s,e.maximum??-1/0),(t.average||t.median)&&null!=s&&(e.history.push(s),t.average?e.average=I(e.history):null!=e.average&&delete e.average,t.median?e.median=b(e.history):null!=e.median&&delete e.median))},D=Object.freeze({SOFT:"SOFT",HARD:"HARD"});class L{pool;opts;nextWorkerNodeKey=0;previousWorkerNodeKey=0;strategyPolicy={dynamicWorkerUsage:!1,dynamicWorkerReady:!0};taskStatisticsRequirements={runTime:S,waitTime:S,elu:S};constructor(e,t=W){this.pool=e,this.opts=t,this.opts={...W,...t},this.choose=this.choose.bind(this)}setTaskStatisticsRequirements(e){this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.runTime,e.runTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.waitTime,e.waitTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.elu,e.elu?.median)}toggleMedianMeasurementStatisticsRequirements(e,t){e.average&&t&&(e.average=!1,e.median=t),e.median&&!t&&(e.average=!0,e.median=t)}resetWorkerNodeKeyProperties(){this.nextWorkerNodeKey=0,this.previousWorkerNodeKey=0}setOptions(e){this.opts={...W,...e},this.setTaskStatisticsRequirements(this.opts)}isWorkerNodeReady(e){return this.pool.workerNodes[e].info.ready}hasWorkerNodeBackPressure(e){return this.pool.hasWorkerNodeBackPressure(e)}isWorkerNodeEligible(e){return this.isWorkerNodeReady(e)&&!this.hasWorkerNodeBackPressure(e)}getWorkerNodeTaskRunTime(e){return this.taskStatisticsRequirements.runTime.median?this.pool.workerNodes[e].usage.runTime.median??0:this.pool.workerNodes[e].usage.runTime.average??0}getWorkerNodeTaskWaitTime(e){return this.taskStatisticsRequirements.waitTime.median?this.pool.workerNodes[e].usage.waitTime.median??0:this.pool.workerNodes[e].usage.waitTime.average??0}getWorkerNodeTaskElu(e){return this.taskStatisticsRequirements.elu.median?this.pool.workerNodes[e].usage.elu.active.median??0:this.pool.workerNodes[e].usage.elu.active.average??0}setPreviousWorkerNodeKey(e){this.previousWorkerNodeKey=e??this.previousWorkerNodeKey}checkNextWorkerNodeEligibility(){this.isWorkerNodeEligible(this.nextWorkerNodeKey)||(this.nextWorkerNodeKey=void 0)}computeDefaultWorkerWeight(){let e=0;for(const t of h()){const s=t.speed.toString().length-1;e+=1/(t.speed/Math.pow(10,s))*Math.pow(10,s)}return Math.round(e/h().length)}}class _ extends L{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:S,elu:{aggregate:!0,average:!0,median:!1}};constructor(e,t=W){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){for(const e of this.pool.workerNodes)delete e.strategyData?.virtualTaskEndTimestamp;return!0}update(e){return this.pool.workerNodes[e].strategyData={virtualTaskEndTimestamp:this.computeWorkerNodeVirtualTaskEndTimestamp(e)},!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.fairShareNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}fairShareNextWorkerNodeKey(){return this.pool.workerNodes.reduce(((e,t,s,r)=>(null==t.strategyData?.virtualTaskEndTimestamp&&(t.strategyData={virtualTaskEndTimestamp:this.computeWorkerNodeVirtualTaskEndTimestamp(s)}),t.strategyData.virtualTaskEndTimestamp<r[e].strategyData.virtualTaskEndTimestamp?s:e)),0)}computeWorkerNodeVirtualTaskEndTimestamp(e){return this.getWorkerNodeVirtualTaskEndTimestamp(e,this.getWorkerNodeVirtualTaskStartTimestamp(e))}getWorkerNodeVirtualTaskEndTimestamp(e,t){return t+(this.opts.measurement===K.elu?this.getWorkerNodeTaskElu(e):this.getWorkerNodeTaskRunTime(e))}getWorkerNodeVirtualTaskStartTimestamp(e){const t=this.pool.workerNodes[e]?.strategyData?.virtualTaskEndTimestamp,s=performance.now();return s<(t??-1/0)?t:s}}class H extends L{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:S,elu:S};roundId=0;defaultWorkerWeight;roundWeights;workerNodeId=0;workerNodeVirtualTaskRunTime=0;constructor(e,t=W){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight(),this.roundWeights=this.getRoundWeights()}reset(){return this.resetWorkerNodeKeyProperties(),this.roundId=0,this.workerNodeId=0,this.workerNodeVirtualTaskRunTime=0,!0}update(){return!0}choose(){for(let e=this.roundId;e<this.roundWeights.length;e++){this.roundId=e;for(let t=this.workerNodeId;t<this.pool.workerNodes.length;t++){this.workerNodeId=t,this.workerNodeId!==this.nextWorkerNodeKey&&0!==this.workerNodeVirtualTaskRunTime&&(this.workerNodeVirtualTaskRunTime=0);const s=this.opts.weights?.[t]??this.defaultWorkerWeight;if(s>=this.roundWeights[e]&&this.workerNodeVirtualTaskRunTime<s)return this.workerNodeVirtualTaskRunTime=this.workerNodeVirtualTaskRunTime+this.getWorkerNodeTaskRunTime(t),this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=t,this.nextWorkerNodeKey}}this.interleavedWeightedRoundRobinNextWorkerNodeId()}interleavedWeightedRoundRobinNextWorkerNodeId(){this.roundId===this.roundWeights.length-1&&this.workerNodeId===this.pool.workerNodes.length-1?(this.roundId=0,this.workerNodeId=0):this.workerNodeId===this.pool.workerNodes.length-1?(this.roundId=this.roundId+1,this.workerNodeId=0):this.workerNodeId=this.workerNodeId+1}remove(e){return 0===this.pool.workerNodes.length&&this.reset(),this.workerNodeId===e&&this.workerNodeId>this.pool.workerNodes.length-1&&(this.workerNodeId=this.pool.workerNodes.length-1),this.previousWorkerNodeKey===e&&this.previousWorkerNodeKey>this.pool.workerNodes.length-1&&(this.previousWorkerNodeKey=this.pool.workerNodes.length-1),!0}setOptions(e){super.setOptions(e),this.roundWeights=this.getRoundWeights()}getRoundWeights(){return null==this.opts.weights?[this.defaultWorkerWeight]:[...new Set(Object.values(this.opts.weights).slice().sort(((e,t)=>e-t)))]}}class j extends L{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:S};constructor(e,t=W){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastBusyNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastBusyNextWorkerNodeKey(){return this.pool.workerNodes.reduce(((e,t,s,r)=>(t.usage.runTime.aggregate??0)+(t.usage.waitTime.aggregate??0)<(r[e].usage.runTime.aggregate??0)+(r[e].usage.waitTime.aggregate??0)?s:e),0)}}class V extends L{constructor(e,t=W){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastUsedNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastUsedNextWorkerNodeKey(){return this.pool.workerNodes.reduce(((e,t,s,r)=>t.usage.tasks.executed+t.usage.tasks.executing+t.usage.tasks.queued<r[e].usage.tasks.executed+r[e].usage.tasks.executing+r[e].usage.tasks.queued?s:e),0)}}class $ extends L{taskStatisticsRequirements={runTime:S,waitTime:S,elu:{aggregate:!0,average:!1,median:!1}};constructor(e,t=W){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastEluNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastEluNextWorkerNodeKey(){return this.pool.workerNodes.reduce(((e,t,s,r)=>(t.usage.elu.active.aggregate??0)<(r[e].usage.elu.active.aggregate??0)?s:e),0)}}class G extends L{constructor(e,t=W){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.resetWorkerNodeKeyProperties(),!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;return this.setPreviousWorkerNodeKey(e),this.roundRobinNextWorkerNodeKey(),e}remove(e){return 0===this.pool.workerNodes.length&&this.reset(),this.nextWorkerNodeKey===e&&this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1),this.previousWorkerNodeKey===e&&this.previousWorkerNodeKey>this.pool.workerNodes.length-1&&(this.previousWorkerNodeKey=this.pool.workerNodes.length-1),!0}roundRobinNextWorkerNodeKey(){return this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,this.nextWorkerNodeKey}}class Y extends L{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:S,elu:S};defaultWorkerWeight;workerNodeVirtualTaskRunTime=0;constructor(e,t=W){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight()}reset(){return this.resetWorkerNodeKeyProperties(),this.workerNodeVirtualTaskRunTime=0,!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.weightedRoundRobinNextWorkerNodeKey()}remove(e){return 0===this.pool.workerNodes.length&&this.reset(),this.nextWorkerNodeKey===e&&(this.workerNodeVirtualTaskRunTime=0,this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1)),this.previousWorkerNodeKey===e&&this.previousWorkerNodeKey>this.pool.workerNodes.length-1&&(this.previousWorkerNodeKey=this.pool.workerNodes.length-1),!0}weightedRoundRobinNextWorkerNodeKey(){const e=this.opts.weights?.[this.nextWorkerNodeKey??this.previousWorkerNodeKey]??this.defaultWorkerWeight;return this.workerNodeVirtualTaskRunTime<e?this.workerNodeVirtualTaskRunTime=this.workerNodeVirtualTaskRunTime+this.getWorkerNodeTaskRunTime(this.nextWorkerNodeKey??this.previousWorkerNodeKey):(this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,this.workerNodeVirtualTaskRunTime=0),this.nextWorkerNodeKey}}class J{workerChoiceStrategy;opts;workerChoiceStrategies;retriesCount=0;constructor(e,t=P.ROUND_ROBIN,s=W){this.workerChoiceStrategy=t,this.opts=s,this.opts={...W,...s},this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[P.ROUND_ROBIN,new(G.bind(this))(e,s)],[P.LEAST_USED,new(V.bind(this))(e,s)],[P.LEAST_BUSY,new(j.bind(this))(e,s)],[P.LEAST_ELU,new($.bind(this))(e,s)],[P.FAIR_SHARE,new(_.bind(this))(e,s)],[P.WEIGHTED_ROUND_ROBIN,new(Y.bind(this))(e,s)],[P.INTERLEAVED_WEIGHTED_ROUND_ROBIN,new(H.bind(this))(e,s)]])}getStrategyPolicy(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).strategyPolicy}getTaskStatisticsRequirements(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).taskStatisticsRequirements}setWorkerChoiceStrategy(e){this.workerChoiceStrategy!==e&&(this.workerChoiceStrategy=e),this.workerChoiceStrategies.get(this.workerChoiceStrategy)?.reset()}update(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).update(e)}execute(){const e=this.workerChoiceStrategies.get(this.workerChoiceStrategy).choose();if(null==e&&this.retriesCount<this.opts.retries)return this.retriesCount++,this.execute();if(null==e)throw new Error(`Worker node key chosen is null or undefined after ${this.retriesCount} retries`);return this.retriesCount=0,e}remove(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).remove(e)}setOptions(e){this.opts={...W,...e};for(const t of this.workerChoiceStrategies.values())t.setOptions(e)}}class X extends Array{size;constructor(e=1024,...t){super(),this.checkSize(e),this.size=e,arguments.length>1&&this.push(...t)}push(...e){const t=super.push(...e);return t>this.size&&super.splice(0,t-this.size),this.length}unshift(...e){return super.unshift(...e)>this.size&&super.splice(this.size,e.length),this.length}concat(...e){const t=super.concat(e);return t.size=this.size,t.length>t.size&&t.splice(0,t.length-t.size),t}splice(e,t,...s){let r=[];if(arguments.length>=3&&null!=t){if(r=super.splice(e,t,...s),this.length>this.size){const e=super.splice(0,this.length-this.size);r=new X(r.length+e.length,...r,...e)}}else r=2===arguments.length?super.splice(e,t):super.splice(e);return r}resize(e){if(this.checkSize(e),0===e)this.length=0;else if(e<this.size)for(let t=e;t<this.size;t++)super.pop();this.size=e}empty(){return 0===this.length}full(){return this.length===this.size}checkSize(e){if(!Number.isSafeInteger(e))throw new TypeError(`Invalid circular array size: ${e} is not a safe integer`);if(e<0)throw new RangeError(`Invalid circular array size: ${e} < 0`)}}class Z{data;next;prev;constructor(e){this.data=e}}class ee{head;tail;size;maxSize;constructor(){this.clear()}push(e){const t=new Z(e);return null==this.tail?this.head=this.tail=t:(t.prev=this.tail,this.tail=this.tail.next=t),this.incrementSize()}unshift(e){const t=new Z(e);return null==this.head?this.head=this.tail=t:(t.next=this.head,this.head=this.head.prev=t),this.incrementSize()}pop(){if(null==this.head)return;const e=this.tail;return this.tail=this.tail.prev,null==this.tail?this.head=void 0:this.tail.next=void 0,--this.size,e?.data}shift(){if(null==this.head)return;const e=this.head;return this.head=this.head.next,null==this.head?this.tail=void 0:this.head.prev=void 0,--this.size,e?.data}peekFirst(){return this.head?.data}peekLast(){return this.tail?.data}clear(){this.head=void 0,this.tail=void 0,this.size=0,this.maxSize=0}[Symbol.iterator](){let e=this.head;return{next:()=>{if(null==e)return{value:void 0,done:!0};const t={value:e.data,done:!1};return e=e.next,t}}}backward(){return{[Symbol.iterator]:()=>{let e=this.tail;return{next:()=>{if(null==e)return{value:void 0,done:!0};const t={value:e.data,done:!1};return e=e.prev,t}}}}}incrementSize(){return++this.size,this.size>this.maxSize&&(this.maxSize=this.size),this.size}}class te{worker;info;usage;strategyData;messageChannel;tasksQueueBackPressureSize;onBackPressure;onEmptyQueue;tasksQueue;onBackPressureStarted;onEmptyQueueCount;taskFunctionsUsage;constructor(e,t){((e,t)=>{if(null==e)throw new TypeError("Cannot construct a worker node without a worker");if(null==t)throw new TypeError("Cannot construct a worker node without a tasks queue back pressure size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot construct a worker node with a tasks queue back pressure size that is not an integer");if(t<=0)throw new RangeError("Cannot construct a worker node with a tasks queue back pressure size that is not a positive integer")})(e,t),this.worker=e,this.info=this.initWorkerInfo(e),this.usage=this.initWorkerUsage(),this.info.type===T.thread&&(this.messageChannel=new s),this.tasksQueueBackPressureSize=t,this.tasksQueue=new ee,this.onBackPressureStarted=!1,this.onEmptyQueueCount=0,this.taskFunctionsUsage=new Map}tasksQueueSize(){return this.tasksQueue.size}enqueueTask(e){const t=this.tasksQueue.push(e);return null!=this.onBackPressure&&this.hasBackPressure()&&!this.onBackPressureStarted&&(this.onBackPressureStarted=!0,this.onBackPressure(this.info.id),this.onBackPressureStarted=!1),t}unshiftTask(e){const t=this.tasksQueue.unshift(e);return null!=this.onBackPressure&&this.hasBackPressure()&&!this.onBackPressureStarted&&(this.onBackPressureStarted=!0,this.onBackPressure(this.info.id),this.onBackPressureStarted=!1),t}dequeueTask(){const e=this.tasksQueue.shift();return null!=this.onEmptyQueue&&0===this.tasksQueue.size&&0===this.onEmptyQueueCount&&this.startOnEmptyQueue().catch(N),e}popTask(){const e=this.tasksQueue.pop();return null!=this.onEmptyQueue&&0===this.tasksQueue.size&&0===this.onEmptyQueueCount&&this.startOnEmptyQueue().catch(N),e}clearTasksQueue(){this.tasksQueue.clear()}hasBackPressure(){return this.tasksQueue.size>=this.tasksQueueBackPressureSize}resetUsage(){this.usage=this.initWorkerUsage(),this.taskFunctionsUsage.clear()}closeChannel(){null!=this.messageChannel&&(this.messageChannel?.port1.unref(),this.messageChannel?.port2.unref(),this.messageChannel?.port1.close(),this.messageChannel?.port2.close(),delete this.messageChannel)}getTaskFunctionWorkerUsage(e){if(!Array.isArray(this.info.taskFunctionNames))throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function names list is not yet defined`);if(Array.isArray(this.info.taskFunctionNames)&&this.info.taskFunctionNames.length<3)throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function names list has less than 3 elements`);return e===f&&(e=this.info.taskFunctionNames[1]),this.taskFunctionsUsage.has(e)||this.taskFunctionsUsage.set(e,this.initTaskFunctionWorkerUsage(e)),this.taskFunctionsUsage.get(e)}deleteTaskFunctionWorkerUsage(e){return this.taskFunctionsUsage.delete(e)}async startOnEmptyQueue(){this.onEmptyQueueCount>0&&(this.usage.tasks.executing>0||this.tasksQueue.size>0)?this.onEmptyQueueCount=0:(++this.onEmptyQueueCount,this.onEmptyQueue?.(this.info.id),await(async e=>{await new Promise((t=>{setTimeout(t,e)}))})(((e=0,t=100)=>{const s=Math.pow(2,e)*t;return s+.2*s*z()})(this.onEmptyQueueCount)),await this.startOnEmptyQueue())}initWorkerInfo(e){return{id:v(e),type:E(e),dynamic:!1,ready:!1}}initWorkerUsage(){const e=()=>this.tasksQueue.size,t=()=>this.tasksQueue.maxSize;return{tasks:{executed:0,executing:0,get queued(){return e()},get maxQueued(){return t()},stolen:0,failed:0},runTime:{history:new X},waitTime:{history:new X},elu:{idle:{history:new X},active:{history:new X}}}}initTaskFunctionWorkerUsage(e){const t=()=>{let t=0;for(const s of this.tasksQueue)(s.name===f&&e===this.info.taskFunctionNames[1]||s.name!==f&&e===s.name)&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},stolen:0,failed:0},runTime:{history:new X},waitTime:{history:new X},elu:{idle:{history:new X},active:{history:new X}}}}}class se{numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;max;taskFunctions;started;starting;startTimestamp;constructor(e,t,s){if(this.numberOfWorkers=e,this.filePath=t,this.opts=s,!this.isMain())throw new Error("Cannot start a pool from a worker with the same type as the pool");this.checkNumberOfWorkers(this.numberOfWorkers),(e=>{if(null==e||"string"!=typeof e||"string"==typeof e&&0===e.trim().length)throw new Error("Please specify a file with a worker implementation");if(!a(e))throw new Error(`Cannot find the worker file '${e}'`)})(this.filePath),this.checkPoolOptions(this.opts),this.chooseWorkerNode=this.chooseWorkerNode.bind(this),this.executeTask=this.executeTask.bind(this),this.enqueueTask=this.enqueueTask.bind(this),!0===this.opts.enableEvents&&(this.emitter=new w),this.workerChoiceStrategyContext=new J(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook(),this.taskFunctions=new Map,this.started=!1,this.starting=!1,!0===this.opts.startWorkers&&this.start(),this.startTimestamp=g.now()}checkNumberOfWorkers(e){if(null==e)throw new Error("Cannot instantiate a pool without specifying the number of workers");if(!Number.isSafeInteger(e))throw new TypeError("Cannot instantiate a pool with a non safe integer number of workers");if(e<0)throw new RangeError("Cannot instantiate a pool with a negative number of workers");if(this.type===p.fixed&&0===e)throw new RangeError("Cannot instantiate a fixed pool with zero worker")}checkPoolOptions(e){if(!C(e))throw new TypeError("Invalid pool options: must be a plain object");this.opts.startWorkers=e.startWorkers??!0,q(e.workerChoiceStrategy),this.opts.workerChoiceStrategy=e.workerChoiceStrategy??P.ROUND_ROBIN,this.checkValidWorkerChoiceStrategyOptions(e.workerChoiceStrategyOptions),this.opts.workerChoiceStrategyOptions={...W,...e.workerChoiceStrategyOptions},this.opts.restartWorkerOnError=e.restartWorkerOnError??!0,this.opts.enableEvents=e.enableEvents??!0,this.opts.enableTasksQueue=e.enableTasksQueue??!1,this.opts.enableTasksQueue&&(U(e.tasksQueueOptions),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e.tasksQueueOptions))}checkValidWorkerChoiceStrategyOptions(e){if(null!=e&&!C(e))throw new TypeError("Invalid worker choice strategy options: must be a plain object");if(null!=e?.retries&&!Number.isSafeInteger(e.retries))throw new TypeError("Invalid worker choice strategy options: retries must be an integer");if(null!=e?.retries&&e.retries<0)throw new RangeError(`Invalid worker choice strategy options: retries '${e.retries}' must be greater or equal than zero`);if(null!=e?.weights&&Object.keys(e.weights).length!==this.maxSize)throw new Error("Invalid worker choice strategy options: must have a weight for each worker node");if(null!=e?.measurement&&!Object.values(K).includes(e.measurement))throw new Error(`Invalid worker choice strategy options: invalid measurement '${e.measurement}'`)}get info(){return{version:"2.7.1",type:this.type,worker:this.worker,started:this.started,ready:this.ready,strategy:this.opts.workerChoiceStrategy,minSize:this.minSize,maxSize:this.maxSize,...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{utilization:F(this.utilization)},workerNodes:this.workerNodes.length,idleWorkerNodes:this.workerNodes.reduce(((e,t)=>0===t.usage.tasks.executing?e+1:e),0),busyWorkerNodes:this.workerNodes.reduce(((e,t)=>t.usage.tasks.executing>0?e+1:e),0),executedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executed),0),executingTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executing),0),...!0===this.opts.enableTasksQueue&&{queuedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.queued),0)},...!0===this.opts.enableTasksQueue&&{maxQueuedTasks:this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.maxQueued??0)),0)},...!0===this.opts.enableTasksQueue&&{backPressure:this.hasBackPressure()},...!0===this.opts.enableTasksQueue&&{stolenTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.stolen),0)},failedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.failed),0),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&{runTime:{minimum:F(Q(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:F(M(...this.workerNodes.map((e=>e.usage.runTime?.maximum??-1/0)))),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.average&&{average:F(I(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&{median:F(b(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:F(Q(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:F(M(...this.workerNodes.map((e=>e.usage.waitTime?.maximum??-1/0)))),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.average&&{average:F(I(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.waitTime.history)),[])))},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&{median:F(b(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.waitTime.history)),[])))}}}}}get ready(){return this.workerNodes.reduce(((e,t)=>!t.info.dynamic&&t.info.ready?e+1:e),0)>=this.minSize}get utilization(){const e=(g.now()-this.startTimestamp)*this.maxSize;return(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)+this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0))/e}get minSize(){return this.numberOfWorkers}get maxSize(){return this.max??this.numberOfWorkers}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Worker message received without worker id");if(null!=e.workerId&&-1===this.getWorkerNodeKeyByWorkerId(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKeyByWorker(e){return this.workerNodes.findIndex((t=>t.worker===e))}getWorkerNodeKeyByWorkerId(e){return this.workerNodes.findIndex((t=>t.info.id===e))}setWorkerChoiceStrategy(e,t){q(e),this.opts.workerChoiceStrategy=e,this.workerChoiceStrategyContext.setWorkerChoiceStrategy(this.opts.workerChoiceStrategy),null!=t&&this.setWorkerChoiceStrategyOptions(t);for(const[e,t]of this.workerNodes.entries())t.resetUsage(),this.sendStatisticsMessageToWorker(e)}setWorkerChoiceStrategyOptions(e){this.checkValidWorkerChoiceStrategyOptions(e),this.opts.workerChoiceStrategyOptions={...W,...e},this.workerChoiceStrategyContext.setOptions(this.opts.workerChoiceStrategyOptions)}enableTasksQueue(e,t){!0!==this.opts.enableTasksQueue||e||(this.unsetTaskStealing(),this.unsetTasksStealingOnBackPressure(),this.flushTasksQueues()),this.opts.enableTasksQueue=e,this.setTasksQueueOptions(t)}setTasksQueueOptions(e){!0===this.opts.enableTasksQueue?(U(e),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e),this.setTasksQueueSize(this.opts.tasksQueueOptions.size),!0===this.opts.tasksQueueOptions.taskStealing?this.setTaskStealing():this.unsetTaskStealing(),!0===this.opts.tasksQueueOptions.tasksStealingOnBackPressure?this.setTasksStealingOnBackPressure():this.unsetTasksStealingOnBackPressure()):null!=this.opts.tasksQueueOptions&&delete this.opts.tasksQueueOptions}buildTasksQueueOptions(e){return{size:Math.pow(this.maxSize,2),concurrency:1,taskStealing:!0,tasksStealingOnBackPressure:!0,...e}}setTasksQueueSize(e){for(const t of this.workerNodes)t.tasksQueueBackPressureSize=e}setTaskStealing(){for(const[e]of this.workerNodes.entries())this.workerNodes[e].onEmptyQueue=this.taskStealingOnEmptyQueue.bind(this)}unsetTaskStealing(){for(const[e]of this.workerNodes.entries())delete this.workerNodes[e].onEmptyQueue}setTasksStealingOnBackPressure(){for(const[e]of this.workerNodes.entries())this.workerNodes[e].onBackPressure=this.tasksStealingOnBackPressure.bind(this)}unsetTasksStealingOnBackPressure(){for(const[e]of this.workerNodes.entries())delete this.workerNodes[e].onBackPressure}get full(){return this.workerNodes.length>=this.maxSize}internalBusy(){return!0===this.opts.enableTasksQueue?-1===this.workerNodes.findIndex((e=>e.info.ready&&e.usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency)):-1===this.workerNodes.findIndex((e=>e.info.ready&&0===e.usage.tasks.executing))}async sendTaskFunctionOperationToWorker(e,t){return await new Promise(((s,r)=>{const i=t=>{this.checkMessageWorkerId(t);const o=this.getWorkerInfo(e).id;null!=t.taskFunctionOperationStatus&&t.workerId===o&&(t.taskFunctionOperationStatus?s(!0):t.taskFunctionOperationStatus||r(new Error(`Task function operation '${t.taskFunctionOperation}' failed on worker ${t.workerId} with error: '${t.workerError?.message}'`)),this.deregisterWorkerMessageListener(this.getWorkerNodeKeyByWorkerId(t.workerId),i))};this.registerWorkerMessageListener(e,i),this.sendToWorker(e,t)}))}async sendTaskFunctionOperationToWorkers(e){return await new Promise(((t,s)=>{const r=new Array,i=e=>{if(this.checkMessageWorkerId(e),null!=e.taskFunctionOperationStatus&&(r.push(e),r.length===this.workerNodes.length)){if(r.every((e=>!0===e.taskFunctionOperationStatus)))t(!0);else if(r.some((e=>!1===e.taskFunctionOperationStatus))){const t=r.find((e=>!1===e.taskFunctionOperationStatus));s(new Error(`Task function operation '${e.taskFunctionOperation}' failed on worker ${t?.workerId} with error: '${t?.workerError?.message}'`))}this.deregisterWorkerMessageListener(this.getWorkerNodeKeyByWorkerId(e.workerId),i)}};for(const[t]of this.workerNodes.entries())this.registerWorkerMessageListener(t,i),this.sendToWorker(t,e)}))}hasTaskFunction(e){for(const t of this.workerNodes)if(Array.isArray(t.info.taskFunctionNames)&&t.info.taskFunctionNames.includes(e))return!0;return!1}async addTaskFunction(e,t){if("string"!=typeof e)throw new TypeError("name argument must be a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("name argument must not be an empty string");if("function"!=typeof t)throw new TypeError("fn argument must be a function");const s=await this.sendTaskFunctionOperationToWorkers({taskFunctionOperation:"add",taskFunctionName:e,taskFunction:t.toString()});return this.taskFunctions.set(e,t),s}async removeTaskFunction(e){if(!this.taskFunctions.has(e))throw new Error("Cannot remove a task function not handled on the pool side");const t=await this.sendTaskFunctionOperationToWorkers({taskFunctionOperation:"remove",taskFunctionName:e});return this.deleteTaskFunctionWorkerUsages(e),this.taskFunctions.delete(e),t}listTaskFunctionNames(){for(const e of this.workerNodes)if(Array.isArray(e.info.taskFunctionNames)&&e.info.taskFunctionNames.length>0)return e.info.taskFunctionNames;return[]}async setDefaultTaskFunction(e){return await this.sendTaskFunctionOperationToWorkers({taskFunctionOperation:"default",taskFunctionName:e})}deleteTaskFunctionWorkerUsages(e){for(const t of this.workerNodes)t.deleteTaskFunctionWorkerUsage(e)}shallExecuteTask(e){return 0===this.tasksQueueSize(e)&&this.workerNodes[e].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency}async execute(e,t,s){return await new Promise(((r,i)=>{if(!this.started)return void i(new Error("Cannot execute a task on not started pool"));if(null!=t&&"string"!=typeof t)return void i(new TypeError("name argument must be a string"));if(null!=t&&"string"==typeof t&&0===t.trim().length)return void i(new TypeError("name argument must not be an empty string"));if(null!=s&&!Array.isArray(s))return void i(new TypeError("transferList argument must be an array"));const o=g.now(),n=this.chooseWorkerNode(),a={name:t??f,data:e??{},transferList:s,timestamp:o,taskId:c()};this.promiseResponseMap.set(a.taskId,{resolve:r,reject:i,workerNodeKey:n}),!1===this.opts.enableTasksQueue||!0===this.opts.enableTasksQueue&&this.shallExecuteTask(n)?this.executeTask(n,a):this.enqueueTask(n,a)}))}start(){for(this.starting=!0;this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.numberOfWorkers;)this.createAndSetupWorkerNode();this.starting=!1,this.started=!0}async destroy(){await Promise.all(this.workerNodes.map((async(e,t)=>{await this.destroyWorkerNode(t)}))),this.emitter?.emit(y.destroy,this.info),this.started=!1}async sendKillMessageToWorker(e){await new Promise(((t,s)=>{this.registerWorkerMessageListener(e,(e=>{this.checkMessageWorkerId(e),"success"===e.kill?t():"failure"===e.kill&&s(new Error(`Kill message handling failed on worker ${e.workerId}`))})),this.sendToWorker(e,{kill:!0})}))}setupHook(){}beforeTaskExecutionHook(e,t){if(null!=this.workerNodes[e]?.usage){const s=this.workerNodes[e].usage;++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t)}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name)){const s=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name);++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t)}}afterTaskExecutionHook(e,t){if(null!=this.workerNodes[e]?.usage){const s=this.workerNodes[e].usage;this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t)}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance?.name)){const s=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance?.name);this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t)}}shallUpdateTaskFunctionWorkerUsage(e){const t=this.getWorkerInfo(e);return null!=t&&Array.isArray(t.taskFunctionNames)&&t.taskFunctionNames.length>2}updateTaskStatisticsWorkerUsage(e,t){const s=e.tasks;null!=s.executing&&s.executing>0&&--s.executing,null==t.workerError?++s.executed:++s.failed}updateRunTimeWorkerUsage(e,t){null==t.workerError&&A(e.runTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime,t.taskPerformance?.runTime??0)}updateWaitTimeWorkerUsage(e,t){const s=g.now(),r=s-(t.timestamp??s);A(e.waitTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime,r)}updateEluWorkerUsage(e,t){if(null!=t.workerError)return;const s=this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu;A(e.elu.active,s,t.taskPerformance?.elu?.active??0),A(e.elu.idle,s,t.taskPerformance?.elu?.idle??0),s.aggregate&&null!=t.taskPerformance?.elu&&(null!=e.elu.utilization?e.elu.utilization=(e.elu.utilization+t.taskPerformance.elu.utilization)/2:e.elu.utilization=t.taskPerformance.elu.utilization)}chooseWorkerNode(){if(this.shallCreateDynamicWorker()){const e=this.createAndSetupDynamicWorkerNode();if(this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerUsage)return e}return this.workerChoiceStrategyContext.execute()}shallCreateDynamicWorker(){return this.type===p.dynamic&&!this.full&&this.internalBusy()}createAndSetupWorkerNode(){const e=this.createWorker();e.on("online",this.opts.onlineHandler??N),e.on("message",this.opts.messageHandler??N),e.on("error",this.opts.errorHandler??N),e.on("error",(t=>{const s=this.getWorkerNodeKeyByWorker(e),r=this.getWorkerInfo(s);r.ready=!1,this.workerNodes[s].closeChannel(),this.emitter?.emit(y.error,t),this.started&&!this.starting&&!0===this.opts.restartWorkerOnError&&(r.dynamic?this.createAndSetupDynamicWorkerNode():this.createAndSetupWorkerNode()),this.started&&!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(s)})),e.on("exit",this.opts.exitHandler??N),e.once("exit",(()=>{this.removeWorkerNode(e)}));const t=this.addWorkerNode(e);return this.afterWorkerNodeSetup(t),t}createAndSetupDynamicWorkerNode(){const e=this.createAndSetupWorkerNode();this.registerWorkerMessageListener(e,(e=>{this.checkMessageWorkerId(e);const t=this.getWorkerNodeKeyByWorkerId(e.workerId),s=this.workerNodes[t].usage;(O(D.HARD,e.kill)||O(D.SOFT,e.kill)&&(!1===this.opts.enableTasksQueue&&0===s.tasks.executing||!0===this.opts.enableTasksQueue&&0===s.tasks.executing&&0===this.tasksQueueSize(t)))&&this.destroyWorkerNode(t).catch((e=>{this.emitter?.emit(y.error,e)}))}));const t=this.getWorkerInfo(e);if(this.sendToWorker(e,{checkActive:!0}),this.taskFunctions.size>0)for(const[t,s]of this.taskFunctions)this.sendTaskFunctionOperationToWorker(e,{taskFunctionOperation:"add",taskFunctionName:t,taskFunction:s.toString()}).catch((e=>{this.emitter?.emit(y.error,e)}));return t.dynamic=!0,(this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerReady||this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerUsage)&&(t.ready=!0),this.checkAndEmitDynamicWorkerCreationEvents(),e}afterWorkerNodeSetup(e){this.registerWorkerMessageListener(e,this.workerListener()),this.sendStartupMessageToWorker(e),this.sendStatisticsMessageToWorker(e),!0===this.opts.enableTasksQueue&&(!0===this.opts.tasksQueueOptions?.taskStealing&&(this.workerNodes[e].onEmptyQueue=this.taskStealingOnEmptyQueue.bind(this)),!0===this.opts.tasksQueueOptions?.tasksStealingOnBackPressure&&(this.workerNodes[e].onBackPressure=this.tasksStealingOnBackPressure.bind(this)))}sendStatisticsMessageToWorker(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate}})}redistributeQueuedTasks(e){for(;this.tasksQueueSize(e)>0;){const t=this.workerNodes.reduce(((e,t,s,r)=>t.info.ready&&t.usage.tasks.queued<r[e].usage.tasks.queued?s:e),0),s=this.dequeueTask(e);this.shallExecuteTask(t)?this.executeTask(t,s):this.enqueueTask(t,s)}}updateTaskStolenStatisticsWorkerUsage(e,t){const s=this.workerNodes[e];if(null!=s?.usage&&++s.usage.tasks.stolen,this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=s.getTaskFunctionWorkerUsage(t)){++s.getTaskFunctionWorkerUsage(t).tasks.stolen}}taskStealingOnEmptyQueue(e){const t=this.getWorkerNodeKeyByWorkerId(e),s=this.workerNodes.slice().sort(((e,t)=>t.usage.tasks.queued-e.usage.tasks.queued)).find((t=>t.info.ready&&t.info.id!==e&&t.usage.tasks.queued>0));if(null!=s){const e=s.popTask();this.shallExecuteTask(t)?this.executeTask(t,e):this.enqueueTask(t,e),this.updateTaskStolenStatisticsWorkerUsage(t,e.name)}}tasksStealingOnBackPressure(e){if(this.opts.tasksQueueOptions?.size<=1)return;const t=this.workerNodes[this.getWorkerNodeKeyByWorkerId(e)],s=this.workerNodes.slice().sort(((e,t)=>e.usage.tasks.queued-t.usage.tasks.queued));for(const[r,i]of s.entries())if(t.usage.tasks.queued>0&&i.info.ready&&i.info.id!==e&&i.usage.tasks.queued<this.opts.tasksQueueOptions?.size-1){const e=t.popTask();this.shallExecuteTask(r)?this.executeTask(r,e):this.enqueueTask(r,e),this.updateTaskStolenStatisticsWorkerUsage(r,e.name)}}workerListener(){return e=>{this.checkMessageWorkerId(e),null!=e.ready&&null!=e.taskFunctionNames?this.handleWorkerReadyResponse(e):null!=e.taskId?this.handleTaskExecutionResponse(e):null!=e.taskFunctionNames&&(this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId)).taskFunctionNames=e.taskFunctionNames)}}handleWorkerReadyResponse(e){if(!1===e.ready)throw new Error(`Worker ${e.workerId} failed to initialize`);const t=this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId));t.ready=e.ready,t.taskFunctionNames=e.taskFunctionNames,this.ready&&this.emitter?.emit(y.ready,this.info)}handleTaskExecutionResponse(e){const{taskId:t,workerError:s,data:r}=e,i=this.promiseResponseMap.get(t);if(null!=i){null!=s?(this.emitter?.emit(y.taskError,s),i.reject(s.message)):i.resolve(r);const o=i.workerNodeKey;this.afterTaskExecutionHook(o,e),this.workerChoiceStrategyContext.update(o),this.promiseResponseMap.delete(t),!0===this.opts.enableTasksQueue&&this.tasksQueueSize(o)>0&&this.workerNodes[o].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&this.executeTask(o,this.dequeueTask(o))}}checkAndEmitTaskExecutionEvents(){this.busy&&this.emitter?.emit(y.busy,this.info)}checkAndEmitTaskQueuingEvents(){this.hasBackPressure()&&this.emitter?.emit(y.backPressure,this.info)}checkAndEmitDynamicWorkerCreationEvents(){this.type===p.dynamic&&this.full&&this.emitter?.emit(y.full,this.info)}getWorkerInfo(e){return this.workerNodes[e].info}addWorkerNode(e){const t=new te(e,this.opts.tasksQueueOptions?.size??Math.pow(this.maxSize,2));this.starting&&(t.info.ready=!0),this.workerNodes.push(t);const s=this.getWorkerNodeKeyByWorker(e);if(-1===s)throw new Error("Worker added not found in worker nodes");return s}removeWorkerNode(e){const t=this.getWorkerNodeKeyByWorker(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategyContext.remove(t))}hasWorkerNodeBackPressure(e){return!0===this.opts.enableTasksQueue&&this.workerNodes[e].hasBackPressure()}hasBackPressure(){return!0===this.opts.enableTasksQueue&&-1===this.workerNodes.findIndex((e=>!e.hasBackPressure()))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(e,t,t.transferList),this.checkAndEmitTaskExecutionEvents()}enqueueTask(e,t){const s=this.workerNodes[e].enqueueTask(t);return this.checkAndEmitTaskQueuingEvents(),s}dequeueTask(e){return this.workerNodes[e].dequeueTask()}tasksQueueSize(e){return this.workerNodes[e].tasksQueueSize()}flushTasksQueue(e){for(;this.tasksQueueSize(e)>0;)this.executeTask(e,this.dequeueTask(e));this.workerNodes[e].clearTasksQueue()}flushTasksQueues(){for(const[e]of this.workerNodes.entries())this.flushTasksQueue(e)}}class re extends se{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}setupHook(){d.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return d.isPrimary}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e].worker,s=new Promise((e=>{t.once("exit",(()=>{e()}))}));t.once("disconnect",(()=>{t.kill()})),await this.sendKillMessageToWorker(e),t.disconnect(),await s}sendToWorker(e,t){this.workerNodes[e].worker.send({...t,workerId:this.workerNodes[e].info.id})}sendStartupMessageToWorker(e){this.sendToWorker(e,{ready:!1})}registerWorkerMessageListener(e,t){this.workerNodes[e].worker.on("message",t)}registerOnceWorkerMessageListener(e,t){this.workerNodes[e].worker.once("message",t)}deregisterWorkerMessageListener(e,t){this.workerNodes[e].worker.off("message",t)}createWorker(){return d.fork(this.opts.env)}get type(){return p.fixed}get worker(){return T.cluster}get busy(){return this.internalBusy()}}class ie extends re{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,B(this.numberOfWorkers,this.max)}get type(){return p.dynamic}get busy(){return this.full&&this.internalBusy()}}class oe extends se{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}isMain(){return r}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e],s=t.worker,r=new Promise((e=>{s.once("exit",(()=>{e()}))}));await this.sendKillMessageToWorker(e),t.closeChannel(),await s.terminate(),await r}sendToWorker(e,t,s){this.workerNodes[e].messageChannel.port1.postMessage({...t,workerId:this.workerNodes[e].info.id},s)}sendStartupMessageToWorker(e){const t=this.workerNodes[e],s=t.messageChannel.port2;t.worker.postMessage({ready:!1,workerId:t.info.id,port:s},[s])}registerWorkerMessageListener(e,t){this.workerNodes[e].messageChannel.port1.on("message",t)}registerOnceWorkerMessageListener(e,t){this.workerNodes[e].messageChannel.port1.once("message",t)}deregisterWorkerMessageListener(e,t){this.workerNodes[e].messageChannel.port1.off("message",t)}createWorker(){return new t(this.filePath,{env:i,...this.opts.workerOptions})}get type(){return p.fixed}get worker(){return T.thread}get busy(){return this.internalBusy()}}class ne extends oe{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,B(this.numberOfWorkers,this.max)}get type(){return p.dynamic}get busy(){return this.full&&this.internalBusy()}}const ae=(e,t)=>{if("string"!=typeof e)throw new TypeError("A taskFunctions parameter object key is not a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("A taskFunctions parameter object key is an empty string");if("function"!=typeof t)throw new TypeError("A taskFunctions parameter object value is not a function")},ue=e=>{if("string"!=typeof e)throw new TypeError("name parameter is not a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("name parameter is an empty string")},he=6e4,ke={killBehavior:D.SOFT,maxInactiveTime:he,killHandler:N};class ce extends m{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,s,r,i=ke){if(super(e),this.isMain=t,this.mainWorker=s,this.opts=i,null==this.isMain)throw new Error("isMain parameter is mandatory");this.checkTaskFunctions(r),this.checkWorkerOptions(this.opts),this.isMain||this.getMainWorker().on("message",this.handleReadyMessage.bind(this))}checkWorkerOptions(e){(e=>{if(null!=e&&!C(e))throw new TypeError("opts worker options parameter is not a plain object");if(null!=e?.killBehavior&&!Object.values(D).includes(e.killBehavior))throw new TypeError(`killBehavior option '${e.killBehavior}' is not valid`);if(null!=e?.maxInactiveTime&&!Number.isSafeInteger(e.maxInactiveTime))throw new TypeError("maxInactiveTime option is not an integer");if(null!=e?.maxInactiveTime&&e.maxInactiveTime<5)throw new TypeError("maxInactiveTime option is not a positive integer greater or equal than 5");if(null!=e?.killHandler&&"function"!=typeof e.killHandler)throw new TypeError("killHandler option is not a function");if(null!=e?.async)throw new Error("async option is deprecated")})(e),this.opts={...ke,...e}}checkTaskFunctions(e){if(null==e)throw new Error("taskFunctions parameter is mandatory");if(this.taskFunctions=new Map,"function"==typeof e){const t=e.bind(this);this.taskFunctions.set(f,t),this.taskFunctions.set("string"==typeof e.name&&e.name.trim().length>0?e.name:"fn1",t)}else{if(!C(e))throw new TypeError("taskFunctions parameter is not a function or a plain object");{let t=!0;for(const[s,r]of Object.entries(e)){ae(s,r);const e=r.bind(this);t&&(this.taskFunctions.set(f,e),t=!1),this.taskFunctions.set(s,e)}if(t)throw new Error("taskFunctions parameter object is empty")}}}hasTaskFunction(e){try{ue(e)}catch(e){return{status:!1,error:e}}return{status:this.taskFunctions.has(e)}}addTaskFunction(e,t){try{if(ue(e),e===f)throw new Error("Cannot add a task function with the default reserved name");if("function"!=typeof t)throw new TypeError("fn parameter is not a function");const s=t.bind(this);return this.taskFunctions.get(e)===this.taskFunctions.get(f)&&this.taskFunctions.set(f,s),this.taskFunctions.set(e,s),this.sendTaskFunctionNamesToMainWorker(),{status:!0}}catch(e){return{status:!1,error:e}}}removeTaskFunction(e){try{if(ue(e),e===f)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(f))throw new Error("Cannot remove the task function used as the default task function");const t=this.taskFunctions.delete(e);return this.sendTaskFunctionNamesToMainWorker(),{status:t}}catch(e){return{status:!1,error:e}}}listTaskFunctionNames(){const e=[...this.taskFunctions.keys()];let t=f;for(const[e,s]of this.taskFunctions)if(e!==f&&s===this.taskFunctions.get(f)){t=e;break}return[e[e.indexOf(f)],t,...e.filter((e=>e!==f&&e!==t))]}setDefaultTaskFunction(e){try{if(ue(e),e===f)throw new Error("Cannot set the default task function reserved name as the default task function");if(!this.taskFunctions.has(e))throw new Error("Cannot set the default task function to a non-existing task function");return this.taskFunctions.set(f,this.taskFunctions.get(e)),this.sendTaskFunctionNamesToMainWorker(),{status:!0}}catch(e){return{status:!1,error:e}}}messageListener(e){this.checkMessageWorkerId(e),null!=e.statistics?this.statistics=e.statistics:null!=e.checkActive?e.checkActive?this.startCheckActive():this.stopCheckActive():null!=e.taskFunctionOperation?this.handleTaskFunctionOperationMessage(e):null!=e.taskId&&null!=e.data?this.run(e):!0===e.kill&&this.handleKillMessage(e)}handleTaskFunctionOperationMessage(e){const{taskFunctionOperation:t,taskFunctionName:s,taskFunction:r}=e;let i;switch(t){case"add":i=this.addTaskFunction(s,new Function(`return ${r}`)());break;case"remove":i=this.removeTaskFunction(s);break;case"default":i=this.setDefaultTaskFunction(s);break;default:i={status:!1,error:new Error("Unknown task operation")}}this.sendToMainWorker({taskFunctionOperation:t,taskFunctionOperationStatus:i.status,taskFunctionName:s,...!i.status&&null!=i?.error&&{workerError:{name:s,message:this.handleError(i.error)}}})}handleKillMessage(e){if(this.stopCheckActive(),R(this.opts.killHandler))(this.opts.killHandler?.()).then((()=>(this.sendToMainWorker({kill:"success"}),null))).catch((()=>{this.sendToMainWorker({kill:"failure"})})).finally((()=>{this.emitDestroy()})).catch(N);else try{this.opts.killHandler?.(),this.sendToMainWorker({kill:"success"})}catch{this.sendToMainWorker({kill:"failure"})}finally{this.emitDestroy()}}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Message worker id is not set");if(null!=e.workerId&&e.workerId!==this.id)throw new Error(`Message worker id ${e.workerId} does not match the worker id ${this.id}`)}startCheckActive(){this.lastTaskTimestamp=g.now(),this.activeInterval=setInterval(this.checkActive.bind(this),(this.opts.maxInactiveTime??he)/2)}stopCheckActive(){null!=this.activeInterval&&(clearInterval(this.activeInterval),delete this.activeInterval)}checkActive(){g.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??he)&&this.sendToMainWorker({kill:this.opts.killBehavior})}getMainWorker(){if(null==this.mainWorker)throw new Error("Main worker not set");return this.mainWorker}sendTaskFunctionNamesToMainWorker(){this.sendToMainWorker({taskFunctionNames:this.listTaskFunctionNames()})}handleError(e){return e instanceof Error?e.message:e}run(e){const{name:t,taskId:s,data:r}=e,i=this.taskFunctions.get(t??f);null!=i?R(i)?this.runInAsyncScope(this.runAsync.bind(this),this,i,e):this.runInAsyncScope(this.runSync.bind(this),this,i,e):this.sendToMainWorker({workerError:{name:t,message:`Task function '${t}' not found`,data:r},taskId:s})}runSync(e,t){const{name:s,taskId:r,data:i}=t;try{let t=this.beginTaskPerformance(s);const o=e(i);t=this.endTaskPerformance(t),this.sendToMainWorker({data:o,taskPerformance:t,taskId:r})}catch(e){this.sendToMainWorker({workerError:{name:s,message:this.handleError(e),data:i},taskId:r})}finally{this.updateLastTaskTimestamp()}}runAsync(e,t){const{name:s,taskId:r,data:i}=t;let o=this.beginTaskPerformance(s);e(i).then((e=>{o=this.endTaskPerformance(o),this.sendToMainWorker({data:e,taskPerformance:o,taskId:r})})).catch((e=>{this.sendToMainWorker({workerError:{name:s,message:this.handleError(e),data:i},taskId:r})})).finally((()=>{this.updateLastTaskTimestamp()})).catch(N)}beginTaskPerformance(e){return this.checkStatistics(),{name:e??f,timestamp:g.now(),...this.statistics.elu&&{elu:g.eventLoopUtilization()}}}endTaskPerformance(e){return this.checkStatistics(),{...e,...this.statistics.runTime&&{runTime:g.now()-e.timestamp},...this.statistics.elu&&{elu:g.eventLoopUtilization(e.elu)}}}checkStatistics(){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set")}updateLastTaskTimestamp(){null!=this.activeInterval&&(this.lastTaskTimestamp=g.now())}}class de extends ce{constructor(e,t={}){super("worker-cluster-pool:poolifier",d.isPrimary,d.worker,e,t)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready)try{this.getMainWorker().on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctionNames:this.listTaskFunctionNames()})}catch{this.sendToMainWorker({ready:!1,taskFunctionNames:this.listTaskFunctionNames()})}}get id(){return this.getMainWorker().id}sendToMainWorker(e){this.getMainWorker().send({...e,workerId:this.id})}}class le extends ce{port;constructor(e,t={}){super("worker-thread-pool:poolifier",r,o,e,t)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready&&null!=e.port)try{this.port=e.port,this.port.on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctionNames:this.listTaskFunctionNames()})}catch{this.sendToMainWorker({ready:!1,taskFunctionNames:this.listTaskFunctionNames()})}}handleKillMessage(e){super.handleKillMessage(e),this.port?.unref(),this.port?.close()}get id(){return n}sendToMainWorker(e){this.port.postMessage({...e,workerId:this.id})}handleError(e){return e}}export{de as ClusterWorker,ie as DynamicClusterPool,ne as DynamicThreadPool,re as FixedClusterPool,oe as FixedThreadPool,D as KillBehaviors,K as Measurements,y as PoolEvents,p as PoolTypes,le as ThreadWorker,P as WorkerChoiceStrategies,T as WorkerTypes,x as availableParallelism};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "poolifier",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.7.1",
|
|
5
5
|
"description": "Fast and small Node.js Worker_Threads and Cluster Worker Pool",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "./lib/index.js",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"pnpm": ">=8.6.0"
|
|
28
28
|
},
|
|
29
29
|
"volta": {
|
|
30
|
-
"node": "20.
|
|
31
|
-
"pnpm": "8.7.
|
|
30
|
+
"node": "20.7.0",
|
|
31
|
+
"pnpm": "8.7.6"
|
|
32
32
|
},
|
|
33
33
|
"repository": {
|
|
34
34
|
"type": "git",
|
|
@@ -91,8 +91,8 @@
|
|
|
91
91
|
"@rollup/plugin-terser": "^0.4.3",
|
|
92
92
|
"@rollup/plugin-typescript": "^11.1.3",
|
|
93
93
|
"@types/node": "^20.6.2",
|
|
94
|
-
"@typescript-eslint/eslint-plugin": "^6.7.
|
|
95
|
-
"@typescript-eslint/parser": "^6.7.
|
|
94
|
+
"@typescript-eslint/eslint-plugin": "^6.7.2",
|
|
95
|
+
"@typescript-eslint/parser": "^6.7.2",
|
|
96
96
|
"benchmark": "^2.1.4",
|
|
97
97
|
"c8": "^8.0.1",
|
|
98
98
|
"eslint": "^8.49.0",
|