poolifier 3.0.14 → 3.1.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 +94 -70
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +1 -1
- package/lib/index.mjs.map +1 -1
- package/package.json +6 -6
package/lib/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { TransferListItem, MessagePort,
|
|
2
|
+
import { TransferListItem, MessagePort, WorkerOptions as WorkerOptions$1, MessageChannel, Worker as Worker$1 } from 'node:worker_threads';
|
|
3
3
|
import { EventEmitter, EventEmitterAsyncResource } from 'node:events';
|
|
4
4
|
import { EventLoopUtilization } from 'node:perf_hooks';
|
|
5
5
|
import { AsyncResource } from 'node:async_hooks';
|
|
6
|
-
import {
|
|
6
|
+
import { ClusterSettings, Worker } from 'node:cluster';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Enumeration of kill behaviors.
|
|
@@ -480,33 +480,50 @@ interface StrategyData {
|
|
|
480
480
|
*/
|
|
481
481
|
interface IWorker {
|
|
482
482
|
/**
|
|
483
|
-
*
|
|
483
|
+
* Cluster worker id.
|
|
484
484
|
*/
|
|
485
485
|
readonly id?: number;
|
|
486
|
+
/**
|
|
487
|
+
* Worker thread worker id.
|
|
488
|
+
*/
|
|
486
489
|
readonly threadId?: number;
|
|
487
490
|
/**
|
|
488
|
-
* Registers an event
|
|
491
|
+
* Registers an event handler.
|
|
489
492
|
*
|
|
490
493
|
* @param event - The event.
|
|
491
494
|
* @param handler - The event handler.
|
|
492
495
|
*/
|
|
493
|
-
readonly on: (
|
|
496
|
+
readonly on: (event: string, handler: OnlineHandler<this> | MessageHandler<this> | ErrorHandler<this> | ExitHandler<this>) => void;
|
|
494
497
|
/**
|
|
495
|
-
* Registers
|
|
498
|
+
* Registers once an event handler.
|
|
496
499
|
*
|
|
497
|
-
* @param event - The
|
|
498
|
-
* @param handler - The
|
|
500
|
+
* @param event - The event.
|
|
501
|
+
* @param handler - The event handler.
|
|
502
|
+
*/
|
|
503
|
+
readonly once: (event: string, handler: OnlineHandler<this> | MessageHandler<this> | ErrorHandler<this> | ExitHandler<this>) => void;
|
|
504
|
+
/**
|
|
505
|
+
* Stop all JavaScript execution in the worker thread as soon as possible.
|
|
506
|
+
* Returns a Promise for the exit code that is fulfilled when the `'exit' event` is emitted.
|
|
507
|
+
*/
|
|
508
|
+
readonly terminate?: () => Promise<number>;
|
|
509
|
+
/**
|
|
510
|
+
* Cluster worker disconnect.
|
|
499
511
|
*/
|
|
500
|
-
readonly
|
|
512
|
+
readonly disconnect?: () => void;
|
|
513
|
+
/**
|
|
514
|
+
* Cluster worker kill.
|
|
515
|
+
*/
|
|
516
|
+
readonly kill?: (signal?: string) => void;
|
|
501
517
|
}
|
|
502
518
|
/**
|
|
503
|
-
* Worker node
|
|
519
|
+
* Worker node options.
|
|
504
520
|
*
|
|
505
521
|
* @internal
|
|
506
522
|
*/
|
|
507
|
-
interface
|
|
508
|
-
|
|
509
|
-
|
|
523
|
+
interface WorkerNodeOptions {
|
|
524
|
+
workerOptions?: WorkerOptions$1;
|
|
525
|
+
env?: Record<string, unknown>;
|
|
526
|
+
tasksQueueBackPressureSize: number;
|
|
510
527
|
}
|
|
511
528
|
/**
|
|
512
529
|
* Worker node interface.
|
|
@@ -534,7 +551,7 @@ interface IWorkerNode<Worker extends IWorker, Data = unknown> extends EventEmitt
|
|
|
534
551
|
*/
|
|
535
552
|
strategyData?: StrategyData;
|
|
536
553
|
/**
|
|
537
|
-
* Message channel (
|
|
554
|
+
* Message channel (worker thread only).
|
|
538
555
|
*/
|
|
539
556
|
readonly messageChannel?: MessageChannel;
|
|
540
557
|
/**
|
|
@@ -589,9 +606,23 @@ interface IWorkerNode<Worker extends IWorker, Data = unknown> extends EventEmitt
|
|
|
589
606
|
*/
|
|
590
607
|
readonly resetUsage: () => void;
|
|
591
608
|
/**
|
|
592
|
-
*
|
|
609
|
+
* Terminates the worker node.
|
|
610
|
+
*/
|
|
611
|
+
readonly terminate: () => Promise<void>;
|
|
612
|
+
/**
|
|
613
|
+
* Registers a worker event handler.
|
|
614
|
+
*
|
|
615
|
+
* @param event - The event.
|
|
616
|
+
* @param handler - The event handler.
|
|
617
|
+
*/
|
|
618
|
+
readonly registerWorkerEventHandler: (event: string, handler: OnlineHandler<Worker> | MessageHandler<Worker> | ErrorHandler<Worker> | ExitHandler<Worker>) => void;
|
|
619
|
+
/**
|
|
620
|
+
* Registers once a worker event handler.
|
|
621
|
+
*
|
|
622
|
+
* @param event - The event.
|
|
623
|
+
* @param handler - The event handler.
|
|
593
624
|
*/
|
|
594
|
-
readonly
|
|
625
|
+
readonly registerOnceWorkerEventHandler: (event: string, handler: OnlineHandler<Worker> | MessageHandler<Worker> | ErrorHandler<Worker> | ExitHandler<Worker>) => void;
|
|
595
626
|
/**
|
|
596
627
|
* Gets task function worker usage statistics.
|
|
597
628
|
*
|
|
@@ -607,6 +638,15 @@ interface IWorkerNode<Worker extends IWorker, Data = unknown> extends EventEmitt
|
|
|
607
638
|
*/
|
|
608
639
|
readonly deleteTaskFunctionWorkerUsage: (name: string) => boolean;
|
|
609
640
|
}
|
|
641
|
+
/**
|
|
642
|
+
* Worker node event detail.
|
|
643
|
+
*
|
|
644
|
+
* @internal
|
|
645
|
+
*/
|
|
646
|
+
interface WorkerNodeEventDetail {
|
|
647
|
+
workerId: number;
|
|
648
|
+
workerNodeKey?: number;
|
|
649
|
+
}
|
|
610
650
|
|
|
611
651
|
/**
|
|
612
652
|
* Enumeration of worker choice strategies.
|
|
@@ -985,6 +1025,24 @@ interface PoolOptions<Worker extends IWorker> {
|
|
|
985
1025
|
* Pool worker node tasks queue options.
|
|
986
1026
|
*/
|
|
987
1027
|
tasksQueueOptions?: TasksQueueOptions;
|
|
1028
|
+
/**
|
|
1029
|
+
* Worker options.
|
|
1030
|
+
*
|
|
1031
|
+
* @see https://nodejs.org/api/worker_threads.html#new-workerfilename-options
|
|
1032
|
+
*/
|
|
1033
|
+
workerOptions?: WorkerOptions$1;
|
|
1034
|
+
/**
|
|
1035
|
+
* Key/value pairs to add to worker process environment.
|
|
1036
|
+
*
|
|
1037
|
+
* @see https://nodejs.org/api/cluster.html#cluster_cluster_fork_env
|
|
1038
|
+
*/
|
|
1039
|
+
env?: Record<string, unknown>;
|
|
1040
|
+
/**
|
|
1041
|
+
* Cluster settings.
|
|
1042
|
+
*
|
|
1043
|
+
* @see https://nodejs.org/api/cluster.html#cluster_cluster_settings
|
|
1044
|
+
*/
|
|
1045
|
+
settings?: ClusterSettings;
|
|
988
1046
|
}
|
|
989
1047
|
/**
|
|
990
1048
|
* Contract definition for a poolifier pool.
|
|
@@ -1328,6 +1386,7 @@ declare abstract class AbstractPool<Worker extends IWorker, Data = unknown, Resp
|
|
|
1328
1386
|
* @returns Worker nodes busyness boolean status.
|
|
1329
1387
|
*/
|
|
1330
1388
|
protected internalBusy(): boolean;
|
|
1389
|
+
private isWorkerNodeBusy;
|
|
1331
1390
|
private sendTaskFunctionOperationToWorker;
|
|
1332
1391
|
private sendTaskFunctionOperationToWorkers;
|
|
1333
1392
|
/** @inheritDoc */
|
|
@@ -1354,7 +1413,7 @@ declare abstract class AbstractPool<Worker extends IWorker, Data = unknown, Resp
|
|
|
1354
1413
|
*
|
|
1355
1414
|
* @param workerNodeKey - The worker node key.
|
|
1356
1415
|
*/
|
|
1357
|
-
protected
|
|
1416
|
+
protected destroyWorkerNode(workerNodeKey: number): Promise<void>;
|
|
1358
1417
|
/**
|
|
1359
1418
|
* Setup hook to execute code before worker nodes are created in the abstract constructor.
|
|
1360
1419
|
* Can be overridden.
|
|
@@ -1415,12 +1474,6 @@ declare abstract class AbstractPool<Worker extends IWorker, Data = unknown, Resp
|
|
|
1415
1474
|
* @param transferList - The optional array of transferable objects.
|
|
1416
1475
|
*/
|
|
1417
1476
|
protected abstract sendToWorker(workerNodeKey: number, message: MessageValue<Data>, transferList?: TransferListItem[]): void;
|
|
1418
|
-
/**
|
|
1419
|
-
* Creates a new worker.
|
|
1420
|
-
*
|
|
1421
|
-
* @returns Newly created worker.
|
|
1422
|
-
*/
|
|
1423
|
-
protected abstract createWorker(): Worker;
|
|
1424
1477
|
/**
|
|
1425
1478
|
* Creates a new, completely set up worker node.
|
|
1426
1479
|
*
|
|
@@ -1473,6 +1526,7 @@ declare abstract class AbstractPool<Worker extends IWorker, Data = unknown, Resp
|
|
|
1473
1526
|
* @param workerNodeKey - The worker node key.
|
|
1474
1527
|
*/
|
|
1475
1528
|
private sendStatisticsMessageToWorker;
|
|
1529
|
+
private handleTask;
|
|
1476
1530
|
private redistributeQueuedTasks;
|
|
1477
1531
|
private updateTaskStolenStatisticsWorkerUsage;
|
|
1478
1532
|
private updateTaskSequentiallyStolenStatisticsWorkerUsage;
|
|
@@ -1499,17 +1553,23 @@ declare abstract class AbstractPool<Worker extends IWorker, Data = unknown, Resp
|
|
|
1499
1553
|
*/
|
|
1500
1554
|
protected getWorkerInfo(workerNodeKey: number): WorkerInfo;
|
|
1501
1555
|
/**
|
|
1502
|
-
*
|
|
1556
|
+
* Creates a worker node.
|
|
1503
1557
|
*
|
|
1504
|
-
* @
|
|
1558
|
+
* @returns The created worker node.
|
|
1559
|
+
*/
|
|
1560
|
+
private createWorkerNode;
|
|
1561
|
+
/**
|
|
1562
|
+
* Adds the given worker node in the pool worker nodes.
|
|
1563
|
+
*
|
|
1564
|
+
* @param workerNode - The worker node.
|
|
1505
1565
|
* @returns The added worker node key.
|
|
1506
1566
|
* @throws {@link https://nodejs.org/api/errors.html#class-error} If the added worker node is not found.
|
|
1507
1567
|
*/
|
|
1508
1568
|
private addWorkerNode;
|
|
1509
1569
|
/**
|
|
1510
|
-
* Removes the
|
|
1570
|
+
* Removes the worker node from the pool worker nodes.
|
|
1511
1571
|
*
|
|
1512
|
-
* @param
|
|
1572
|
+
* @param workerNode - The worker node.
|
|
1513
1573
|
*/
|
|
1514
1574
|
private removeWorkerNode;
|
|
1515
1575
|
protected flagWorkerNodeAsNotReady(workerNodeKey: number): void;
|
|
@@ -1530,23 +1590,6 @@ declare abstract class AbstractPool<Worker extends IWorker, Data = unknown, Resp
|
|
|
1530
1590
|
private flushTasksQueues;
|
|
1531
1591
|
}
|
|
1532
1592
|
|
|
1533
|
-
/**
|
|
1534
|
-
* Options for a poolifier cluster pool.
|
|
1535
|
-
*/
|
|
1536
|
-
interface ClusterPoolOptions extends PoolOptions<Worker> {
|
|
1537
|
-
/**
|
|
1538
|
-
* Key/value pairs to add to worker process environment.
|
|
1539
|
-
*
|
|
1540
|
-
* @see https://nodejs.org/api/cluster.html#cluster_cluster_fork_env
|
|
1541
|
-
*/
|
|
1542
|
-
env?: Record<string, unknown>;
|
|
1543
|
-
/**
|
|
1544
|
-
* Cluster settings.
|
|
1545
|
-
*
|
|
1546
|
-
* @see https://nodejs.org/api/cluster.html#cluster_cluster_settings
|
|
1547
|
-
*/
|
|
1548
|
-
settings?: ClusterSettings;
|
|
1549
|
-
}
|
|
1550
1593
|
/**
|
|
1551
1594
|
* A cluster pool with a fixed number of workers.
|
|
1552
1595
|
*
|
|
@@ -1556,7 +1599,7 @@ interface ClusterPoolOptions extends PoolOptions<Worker> {
|
|
|
1556
1599
|
* @since 2.0.0
|
|
1557
1600
|
*/
|
|
1558
1601
|
declare class FixedClusterPool<Data = unknown, Response = unknown> extends AbstractPool<Worker, Data, Response> {
|
|
1559
|
-
protected readonly opts:
|
|
1602
|
+
protected readonly opts: PoolOptions<Worker>;
|
|
1560
1603
|
/**
|
|
1561
1604
|
* Constructs a new poolifier fixed cluster pool.
|
|
1562
1605
|
*
|
|
@@ -1564,14 +1607,12 @@ declare class FixedClusterPool<Data = unknown, Response = unknown> extends Abstr
|
|
|
1564
1607
|
* @param filePath - Path to an implementation of a `ClusterWorker` file, which can be relative or absolute.
|
|
1565
1608
|
* @param opts - Options for this fixed cluster pool.
|
|
1566
1609
|
*/
|
|
1567
|
-
constructor(numberOfWorkers: number, filePath: string, opts?:
|
|
1610
|
+
constructor(numberOfWorkers: number, filePath: string, opts?: PoolOptions<Worker>);
|
|
1568
1611
|
/** @inheritDoc */
|
|
1569
1612
|
protected setupHook(): void;
|
|
1570
1613
|
/** @inheritDoc */
|
|
1571
1614
|
protected isMain(): boolean;
|
|
1572
1615
|
/** @inheritDoc */
|
|
1573
|
-
protected destroyWorkerNode(workerNodeKey: number): Promise<void>;
|
|
1574
|
-
/** @inheritDoc */
|
|
1575
1616
|
protected sendToWorker(workerNodeKey: number, message: MessageValue<Data>): void;
|
|
1576
1617
|
/** @inheritDoc */
|
|
1577
1618
|
protected sendStartupMessageToWorker(workerNodeKey: number): void;
|
|
@@ -1582,8 +1623,6 @@ declare class FixedClusterPool<Data = unknown, Response = unknown> extends Abstr
|
|
|
1582
1623
|
/** @inheritDoc */
|
|
1583
1624
|
protected deregisterWorkerMessageListener<Message extends Data | Response>(workerNodeKey: number, listener: (message: MessageValue<Message>) => void): void;
|
|
1584
1625
|
/** @inheritDoc */
|
|
1585
|
-
protected createWorker(): Worker;
|
|
1586
|
-
/** @inheritDoc */
|
|
1587
1626
|
protected get type(): PoolType;
|
|
1588
1627
|
/** @inheritDoc */
|
|
1589
1628
|
protected get worker(): WorkerType;
|
|
@@ -1612,24 +1651,13 @@ declare class DynamicClusterPool<Data = unknown, Response = unknown> extends Fix
|
|
|
1612
1651
|
* @param filePath - Path to an implementation of a `ClusterWorker` file, which can be relative or absolute.
|
|
1613
1652
|
* @param opts - Options for this dynamic cluster pool.
|
|
1614
1653
|
*/
|
|
1615
|
-
constructor(min: number, max: number, filePath: string, opts?:
|
|
1654
|
+
constructor(min: number, max: number, filePath: string, opts?: PoolOptions<Worker>);
|
|
1616
1655
|
/** @inheritDoc */
|
|
1617
1656
|
protected get type(): PoolType;
|
|
1618
1657
|
/** @inheritDoc */
|
|
1619
1658
|
protected get busy(): boolean;
|
|
1620
1659
|
}
|
|
1621
1660
|
|
|
1622
|
-
/**
|
|
1623
|
-
* Options for a poolifier thread pool.
|
|
1624
|
-
*/
|
|
1625
|
-
interface ThreadPoolOptions extends PoolOptions<Worker$1> {
|
|
1626
|
-
/**
|
|
1627
|
-
* Worker options.
|
|
1628
|
-
*
|
|
1629
|
-
* @see https://nodejs.org/api/worker_threads.html#new-workerfilename-options
|
|
1630
|
-
*/
|
|
1631
|
-
workerOptions?: WorkerOptions$1;
|
|
1632
|
-
}
|
|
1633
1661
|
/**
|
|
1634
1662
|
* A thread pool with a fixed number of threads.
|
|
1635
1663
|
*
|
|
@@ -1639,7 +1667,7 @@ interface ThreadPoolOptions extends PoolOptions<Worker$1> {
|
|
|
1639
1667
|
* @since 0.0.1
|
|
1640
1668
|
*/
|
|
1641
1669
|
declare class FixedThreadPool<Data = unknown, Response = unknown> extends AbstractPool<Worker$1, Data, Response> {
|
|
1642
|
-
protected readonly opts:
|
|
1670
|
+
protected readonly opts: PoolOptions<Worker$1>;
|
|
1643
1671
|
/**
|
|
1644
1672
|
* Constructs a new poolifier fixed thread pool.
|
|
1645
1673
|
*
|
|
@@ -1647,12 +1675,10 @@ declare class FixedThreadPool<Data = unknown, Response = unknown> extends Abstra
|
|
|
1647
1675
|
* @param filePath - Path to an implementation of a `ThreadWorker` file, which can be relative or absolute.
|
|
1648
1676
|
* @param opts - Options for this fixed thread pool.
|
|
1649
1677
|
*/
|
|
1650
|
-
constructor(numberOfThreads: number, filePath: string, opts?:
|
|
1678
|
+
constructor(numberOfThreads: number, filePath: string, opts?: PoolOptions<Worker$1>);
|
|
1651
1679
|
/** @inheritDoc */
|
|
1652
1680
|
protected isMain(): boolean;
|
|
1653
1681
|
/** @inheritDoc */
|
|
1654
|
-
protected destroyWorkerNode(workerNodeKey: number): Promise<void>;
|
|
1655
|
-
/** @inheritDoc */
|
|
1656
1682
|
protected sendToWorker(workerNodeKey: number, message: MessageValue<Data>, transferList?: TransferListItem[]): void;
|
|
1657
1683
|
/** @inheritDoc */
|
|
1658
1684
|
protected sendStartupMessageToWorker(workerNodeKey: number): void;
|
|
@@ -1663,8 +1689,6 @@ declare class FixedThreadPool<Data = unknown, Response = unknown> extends Abstra
|
|
|
1663
1689
|
/** @inheritDoc */
|
|
1664
1690
|
protected deregisterWorkerMessageListener<Message extends Data | Response>(workerNodeKey: number, listener: (message: MessageValue<Message>) => void): void;
|
|
1665
1691
|
/** @inheritDoc */
|
|
1666
|
-
protected createWorker(): Worker$1;
|
|
1667
|
-
/** @inheritDoc */
|
|
1668
1692
|
protected get type(): PoolType;
|
|
1669
1693
|
/** @inheritDoc */
|
|
1670
1694
|
protected get worker(): WorkerType;
|
|
@@ -1693,7 +1717,7 @@ declare class DynamicThreadPool<Data = unknown, Response = unknown> extends Fixe
|
|
|
1693
1717
|
* @param filePath - Path to an implementation of a `ThreadWorker` file, which can be relative or absolute.
|
|
1694
1718
|
* @param opts - Options for this dynamic thread pool.
|
|
1695
1719
|
*/
|
|
1696
|
-
constructor(min: number, max: number, filePath: string, opts?:
|
|
1720
|
+
constructor(min: number, max: number, filePath: string, opts?: PoolOptions<Worker$1>);
|
|
1697
1721
|
/** @inheritDoc */
|
|
1698
1722
|
protected get type(): PoolType;
|
|
1699
1723
|
/** @inheritDoc */
|
|
@@ -2034,4 +2058,4 @@ declare class Deque<T> {
|
|
|
2034
2058
|
*/
|
|
2035
2059
|
declare const availableParallelism: () => number;
|
|
2036
2060
|
|
|
2037
|
-
export { AbstractPool, AbstractWorker, CircularArray,
|
|
2061
|
+
export { AbstractPool, AbstractWorker, CircularArray, 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, 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, ThreadWorker, WorkerChoiceStrategies, type WorkerChoiceStrategy, WorkerChoiceStrategyContext, type WorkerChoiceStrategyOptions, type WorkerError, type WorkerInfo, type WorkerNodeEventDetail, type WorkerNodeOptions, type WorkerOptions, type WorkerStatistics, type WorkerType, WorkerTypes, type WorkerUsage, type Writable, availableParallelism };
|
package/lib/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("node:fs"),t=require("node:os"),s=require("node:crypto"),r=require("node:cluster"),i=require("node:worker_threads"),o=require("node:perf_hooks"),n=require("node:events"),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(t);const k=Object.freeze({fixed:"fixed",dynamic:"dynamic"}),d=Object.freeze({ready:"ready",busy:"busy",full:"full",destroy:"destroy",error:"error",taskError:"taskError",backPressure:"backPressure"}),c=Object.freeze({thread:"thread",cluster:"cluster"}),l="default",g=Object.freeze((()=>{})),m={retries:6,runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},p={aggregate:!1,average:!1,median:!1},w=e=>e instanceof i.Worker?c.thread:e instanceof r.Worker?c.cluster:void 0,y=e=>e instanceof i.Worker?e.threadId:e instanceof r.Worker?e.id:void 0,T=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,f=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},W=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),S=(e,t)=>t===e,x=e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name,v=()=>s.getRandomValues(new Uint32Array(1))[0]/4294967296,E=(...e)=>e.reduce(((e,t)=>e<t?e:t),1/0),I=(...e)=>e.reduce(((e,t)=>e>t?e:t),-1/0),F=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"}),b=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"}),R=(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")},C=e=>{if(null!=e&&!Object.values(F).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)},O=e=>{if(null!=e&&!W(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`)},z=(e,t,s)=>{t.aggregate&&(e.aggregate=(e.aggregate??0)+s,e.minimum=E(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=T(e.history):null!=e.average&&delete e.average,t.median?e.median=f(e.history):null!=e.median&&delete e.median))},M=Object.freeze({SOFT:"SOFT",HARD:"HARD"});class P{pool;opts;nextWorkerNodeKey=0;previousWorkerNodeKey=0;strategyPolicy={dynamicWorkerUsage:!1,dynamicWorkerReady:!0};taskStatisticsRequirements={runTime:p,waitTime:p,elu:p};constructor(e,t=m){this.pool=e,this.opts=t,this.opts={...m,...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={...m,...e},this.setTaskStatisticsRequirements(this.opts)}hasPoolWorkerNodesReady(){return this.pool.workerNodes.some((e=>e.info.ready))}isWorkerNodeReady(e){return this.pool.workerNodes[e]?.info?.ready??!1}checkNextWorkerNodeReadiness(){this.isWorkerNodeReady(this.nextWorkerNodeKey)||delete this.nextWorkerNodeKey}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}computeDefaultWorkerWeight(){let e=0;for(const s of t.cpus()){const t=s.speed.toString().length-1;e+=1/(s.speed/Math.pow(10,t))*Math.pow(10,t)}return Math.round(e/t.cpus().length)}}class q extends P{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:p,elu:{aggregate:!0,average:!0,median:!1}};constructor(e,t=m){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)}),this.isWorkerNodeReady(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===b.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 K extends P{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:p,elu:p};roundId=0;defaultWorkerWeight;roundWeights;workerNodeId=0;workerNodeVirtualTaskRunTime=0;constructor(e,t=m){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(this.isWorkerNodeReady(t)&&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 U extends P{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:p};constructor(e,t=m){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)=>this.isWorkerNodeReady(s)&&(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 A extends P{constructor(e,t=m){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)=>this.isWorkerNodeReady(s)&&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:p,waitTime:p,elu:{aggregate:!0,average:!1,median:!1}};constructor(e,t=m){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)=>this.isWorkerNodeReady(s)&&(t.usage.elu.active.aggregate??0)<(r[e].usage.elu.active.aggregate??0)?s:e),0)}}class B extends P{constructor(e,t=m){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(),this.checkNextWorkerNodeReadiness(),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 D extends P{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:p,elu:p};defaultWorkerWeight;workerNodeVirtualTaskRunTime=0;constructor(e,t=m){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(),this.checkNextWorkerNodeReadiness(),this.nextWorkerNodeKey}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 L{workerChoiceStrategy;opts;workerChoiceStrategies;constructor(e,t=F.ROUND_ROBIN,s=m){this.workerChoiceStrategy=t,this.opts=s,this.opts={...m,...s},this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[F.ROUND_ROBIN,new(B.bind(this))(e,s)],[F.LEAST_USED,new(A.bind(this))(e,s)],[F.LEAST_BUSY,new(U.bind(this))(e,s)],[F.LEAST_ELU,new(Q.bind(this))(e,s)],[F.FAIR_SHARE,new(q.bind(this))(e,s)],[F.WEIGHTED_ROUND_ROBIN,new(D.bind(this))(e,s)],[F.INTERLEAVED_WEIGHTED_ROUND_ROBIN,new(K.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);let t;const s=1e4;let r=0,i=0,o=0;do{e.hasPoolWorkerNodesReady()&&(t=e.choose(),i>0&&o++,i++),r++}while(r<s&&(!e.hasPoolWorkerNodesReady()||null==t&&o<this.opts.retries));if(r>=s)throw new RangeError("Worker choice strategy consecutive executions has exceeded the maximum of 10000");if(null==t)throw new Error(`Worker node key chosen is null or undefined after ${o} retries`);return t}remove(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).remove(e)}setOptions(e){this.opts={...m,...e};for(const t of this.workerChoiceStrategies.values())t.setOptions(e)}}class _ 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 _(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 j{data;next;prev;constructor(e){this.data=e}}class H{head;tail;size;maxSize;constructor(){this.clear()}push(e){const t=new j(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 j(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?delete this.head:delete this.tail.next,--this.size,e?.data}shift(){if(null==this.head)return;const e=this.head;return this.head=this.head.next,null==this.head?delete this.tail:delete this.head.prev,--this.size,e?.data}peekFirst(){return this.head?.data}peekLast(){return this.tail?.data}clear(){delete this.head,delete this.tail,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 V extends n.EventEmitter{worker;info;usage;strategyData;messageChannel;tasksQueueBackPressureSize;tasksQueue;onBackPressureStarted;taskFunctionsUsage;constructor(e,t){super(),((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===c.thread&&(this.messageChannel=new i.MessageChannel),this.tasksQueueBackPressureSize=t,this.tasksQueue=new H,this.onBackPressureStarted=!1,this.taskFunctionsUsage=new Map}tasksQueueSize(){return this.tasksQueue.size}enqueueTask(e){const t=this.tasksQueue.push(e);return this.hasBackPressure()&&!this.onBackPressureStarted&&(this.onBackPressureStarted=!0,this.emit("backPressure",{workerId:this.info.id}),this.onBackPressureStarted=!1),t}unshiftTask(e){const t=this.tasksQueue.unshift(e);return this.hasBackPressure()&&!this.onBackPressureStarted&&(this.onBackPressureStarted=!0,this.emit("backPressure",{workerId:this.info.id}),this.onBackPressureStarted=!1),t}dequeueTask(){return this.tasksQueue.shift()}popTask(){return this.tasksQueue.pop()}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===l&&(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)}initWorkerInfo(e){return{id:y(e),type:w(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()},sequentiallyStolen:0,stolen:0,failed:0},runTime:{history:new _},waitTime:{history:new _},elu:{idle:{history:new _},active:{history:new _}}}}initTaskFunctionWorkerUsage(e){const t=()=>{let t=0;for(const s of this.tasksQueue)(s.name===l&&e===this.info.taskFunctionNames[1]||s.name!==l&&e===s.name)&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},sequentiallyStolen:0,stolen:0,failed:0},runTime:{history:new _},waitTime:{history:new _},elu:{idle:{history:new _},active:{history:new _}}}}}class ${numberOfWorkers;filePath;opts;workerNodes=[];emitter;max;promiseResponseMap=new Map;workerChoiceStrategyContext;taskFunctions;started;starting;destroying;readyEventEmitted;startTimestamp;constructor(t,s,r){if(this.numberOfWorkers=t,this.filePath=s,this.opts=r,!this.isMain())throw new Error("Cannot start a pool from a worker with the same type as the pool");(t=>{if(!e.existsSync(t))throw new Error(`Cannot find the worker file '${t}'`)})(this.filePath),this.checkNumberOfWorkers(this.numberOfWorkers),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.initializeEventEmitter(),this.workerChoiceStrategyContext=new L(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook(),this.taskFunctions=new Map,this.started=!1,this.starting=!1,this.destroying=!1,this.readyEventEmitted=!1,!0===this.opts.startWorkers&&this.start(),this.startTimestamp=o.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(!W(e))throw new TypeError("Invalid pool options: must be a plain object");this.opts.startWorkers=e.startWorkers??!0,C(e.workerChoiceStrategy),this.opts.workerChoiceStrategy=e.workerChoiceStrategy??F.ROUND_ROBIN,this.checkValidWorkerChoiceStrategyOptions(e.workerChoiceStrategyOptions),this.opts.workerChoiceStrategyOptions={...m,...e.workerChoiceStrategyOptions},this.opts.restartWorkerOnError=e.restartWorkerOnError??!0,this.opts.enableEvents=e.enableEvents??!0,this.opts.enableTasksQueue=e.enableTasksQueue??!1,this.opts.enableTasksQueue&&(O(e.tasksQueueOptions),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e.tasksQueueOptions))}checkValidWorkerChoiceStrategyOptions(e){if(null!=e&&!W(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(b).includes(e.measurement))throw new Error(`Invalid worker choice strategy options: invalid measurement '${e.measurement}'`)}initializeEventEmitter(){this.emitter=new n.EventEmitterAsyncResource({name:`poolifier:${this.type}-${this.worker}-pool`})}get info(){return{version:"3.0.14",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(E(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:N(I(...this.workerNodes.map((e=>e.usage.runTime?.maximum??-1/0)))),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.average&&{average:N(T(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&{median:N(f(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:N(E(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:N(I(...this.workerNodes.map((e=>e.usage.waitTime?.maximum??-1/0)))),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.average&&{average:N(T(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.waitTime.history)),[])))},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&{median:N(f(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=(o.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(-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){C(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={...m,...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?(O(e),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e),this.setTasksQueueSize(this.opts.tasksQueueOptions.size),!0===this.opts.tasksQueueOptions.taskStealing?(this.unsetTaskStealing(),this.setTaskStealing()):this.unsetTaskStealing(),!0===this.opts.tasksQueueOptions.tasksStealingOnBackPressure?(this.unsetTasksStealingOnBackPressure(),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].on("idleWorkerNode",this.handleIdleWorkerNodeEvent)}unsetTaskStealing(){for(const[e]of this.workerNodes.entries())this.workerNodes[e].off("idleWorkerNode",this.handleIdleWorkerNodeEvent)}setTasksStealingOnBackPressure(){for(const[e]of this.workerNodes.entries())this.workerNodes[e].on("backPressure",this.handleBackPressureEvent)}unsetTasksStealingOnBackPressure(){for(const[e]of this.workerNodes.entries())this.workerNodes[e].off("backPressure",this.handleBackPressureEvent)}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,r){return await new Promise(((i,n)=>{if(!this.started)return void n(new Error("Cannot execute a task on not started pool"));if(this.destroying)return void n(new Error("Cannot execute a task on destroying pool"));if(null!=t&&"string"!=typeof t)return void n(new TypeError("name argument must be a string"));if(null!=t&&"string"==typeof t&&0===t.trim().length)return void n(new TypeError("name argument must not be an empty string"));if(null!=r&&!Array.isArray(r))return void n(new TypeError("transferList argument must be an array"));const u=o.performance.now(),h=this.chooseWorkerNode(),k={name:t??l,data:e??{},transferList:r,timestamp:u,taskId:s.randomUUID()};this.promiseResponseMap.set(k.taskId,{resolve:i,reject:n,workerNodeKey:h,...null!=this.emitter&&{asyncResource:new a.AsyncResource("poolifier:task",{triggerAsyncId:this.emitter.asyncId,requireManualDestroy:!0})}}),!1===this.opts.enableTasksQueue||!0===this.opts.enableTasksQueue&&this.shallExecuteTask(h)?this.executeTask(h,k):this.enqueueTask(h,k)}))}start(){if(this.started)throw new Error("Cannot start an already started pool");if(this.starting)throw new Error("Cannot start an already starting pool");if(this.destroying)throw new Error("Cannot start a destroying pool");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(){if(!this.started)throw new Error("Cannot destroy an already destroyed pool");if(this.starting)throw new Error("Cannot destroy an starting pool");if(this.destroying)throw new Error("Cannot destroy an already destroying pool");this.destroying=!0,await Promise.all(this.workerNodes.map((async(e,t)=>{await this.destroyWorkerNode(t)}))),this.emitter?.emit(d.destroy,this.info),this.emitter?.emitDestroy(),this.emitter?.removeAllListeners(),this.readyEventEmitted=!1,this.destroying=!1,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&&z(e.runTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime,t.taskPerformance?.runTime??0)}updateWaitTimeWorkerUsage(e,t){const s=o.performance.now(),r=s-(t.timestamp??s);z(e.waitTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime,r)}updateEluWorkerUsage(e,t){if(null!=t.workerError)return;const s=this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu;z(e.elu.active,s,t.taskPerformance?.elu?.active??0),z(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??g),e.on("message",this.opts.messageHandler??g),e.on("error",this.opts.errorHandler??g),e.on("error",(t=>{const s=this.getWorkerNodeKeyByWorker(e);this.flagWorkerNodeAsNotReady(s);const r=this.getWorkerInfo(s);this.emitter?.emit(d.error,t),this.workerNodes[s].closeChannel(),!this.started||this.starting||this.destroying||!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??g),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;(S(M.HARD,e.kill)||S(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.flagWorkerNodeAsNotReady(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.workerMessageListener),this.sendStartupMessageToWorker(e),this.sendStatisticsMessageToWorker(e),!0===this.opts.enableTasksQueue&&(!0===this.opts.tasksQueueOptions?.taskStealing&&this.workerNodes[e].on("idleWorkerNode",this.handleIdleWorkerNodeEvent),!0===this.opts.tasksQueueOptions?.tasksStealingOnBackPressure&&this.workerNodes[e].on("backPressure",this.handleBackPressureEvent))}sendStatisticsMessageToWorker(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate}})}redistributeQueuedTasks(e){if(!(this.workerNodes.length<=1))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}}updateTaskSequentiallyStolenStatisticsWorkerUsage(e){const t=this.workerNodes[e];null!=t?.usage&&++t.usage.tasks.sequentiallyStolen}updateTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(e,t){const s=this.workerNodes[e];if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=s.getTaskFunctionWorkerUsage(t)){++s.getTaskFunctionWorkerUsage(t).tasks.sequentiallyStolen}}resetTaskSequentiallyStolenStatisticsWorkerUsage(e){const t=this.workerNodes[e];null!=t?.usage&&(t.usage.tasks.sequentiallyStolen=0)}resetTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(e,t){const s=this.workerNodes[e];if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=s.getTaskFunctionWorkerUsage(t)){s.getTaskFunctionWorkerUsage(t).tasks.sequentiallyStolen=0}}handleIdleWorkerNodeEvent=(e,t)=>{if(this.workerNodes.length<=1)return;const{workerNodeKey:s}=e;if(null==s)throw new Error("WorkerNode event detail workerNodeKey attribute must be defined");const r=this.workerNodes[s].usage.tasks;if(null!=t&&r.sequentiallyStolen>0&&(r.executing>0||this.tasksQueueSize(s)>0)){for(const e of this.workerNodes[s].info.taskFunctionNames)this.resetTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(s,e);return void this.resetTaskSequentiallyStolenStatisticsWorkerUsage(s)}const i=this.workerNodeStealTask(s);if(this.shallUpdateTaskFunctionWorkerUsage(s)&&null!=i){const e=this.workerNodes[s].getTaskFunctionWorkerUsage(i.name)?.tasks;0===e.sequentiallyStolen||null!=t&&t.name===i.name&&e.sequentiallyStolen>0?this.updateTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(s,i.name):this.resetTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(s,i.name)}(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()})(r.sequentiallyStolen)).then((()=>{this.handleIdleWorkerNodeEvent(e,i)})).catch(g)};workerNodeStealTask=e=>{const t=this.workerNodes.slice().sort(((e,t)=>t.usage.tasks.queued-e.usage.tasks.queued)).find(((t,s)=>t.info.ready&&s!==e&&t.usage.tasks.queued>0));if(null!=t){const s=t.popTask();return this.shallExecuteTask(e)?this.executeTask(e,s):this.enqueueTask(e,s),this.updateTaskSequentiallyStolenStatisticsWorkerUsage(e),this.updateTaskStolenStatisticsWorkerUsage(e,s.name),s}};handleBackPressureEvent=e=>{if(this.workerNodes.length<=1)return;const{workerId:t}=e;if(this.opts.tasksQueueOptions?.size<=1)return;const s=this.workerNodes[this.getWorkerNodeKeyByWorkerId(t)],r=this.workerNodes.slice().sort(((e,t)=>e.usage.tasks.queued-t.usage.tasks.queued));for(const[e,i]of r.entries())if(s.usage.tasks.queued>0&&i.info.ready&&i.info.id!==t&&i.usage.tasks.queued<this.opts.tasksQueueOptions?.size-1){const t=s.popTask();this.shallExecuteTask(e)?this.executeTask(e,t):this.enqueueTask(e,t),this.updateTaskStolenStatisticsWorkerUsage(e,t.name)}};workerMessageListener=e=>{this.checkMessageWorkerId(e);const{workerId:t,ready:s,taskId:r,taskFunctionNames:i}=e;null!=s&&null!=i?this.handleWorkerReadyResponse(e):null!=r?this.handleTaskExecutionResponse(e):null!=i&&(this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(t)).taskFunctionNames=i)};handleWorkerReadyResponse(e){const{workerId:t,ready:s,taskFunctionNames:r}=e;if(!1===s)throw new Error(`Worker ${t} failed to initialize`);const i=this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(t));i.ready=s,i.taskFunctionNames=r,!this.readyEventEmitted&&this.ready&&(this.readyEventEmitted=!0,this.emitter?.emit(d.ready,this.info))}handleTaskExecutionResponse(e){const{workerId:t,taskId:s,workerError:r,data:i}=e,o=this.promiseResponseMap.get(s);if(null!=o){const{resolve:n,reject:a,workerNodeKey:u,asyncResource:h}=o;if(null!=r?(this.emitter?.emit(d.taskError,r),null!=h?h.runInAsyncScope(a,this.emitter,r.message):a(r.message)):null!=h?h.runInAsyncScope(n,this.emitter,i):n(i),h?.emitDestroy(),this.afterTaskExecutionHook(u,e),this.workerChoiceStrategyContext.update(u),this.promiseResponseMap.delete(s),!0===this.opts.enableTasksQueue){const e=this.workerNodes[u].usage.tasks;this.tasksQueueSize(u)>0&&e.executing<this.opts.tasksQueueOptions?.concurrency&&this.executeTask(u,this.dequeueTask(u)),0===e.executing&&0===this.tasksQueueSize(u)&&0===e.sequentiallyStolen&&this.workerNodes[u].emit("idleWorkerNode",{workerId:t,workerNodeKey:u})}}}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 V(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))}flagWorkerNodeAsNotReady(e){this.getWorkerInfo(e).ready=!1}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 G extends ${opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}setupHook(){r.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return r.isPrimary}async destroyWorkerNode(e){this.flagWorkerNodeAsNotReady(e),this.flushTasksQueue(e);const t=this.workerNodes[e],s=t.worker,r=new Promise((e=>{s.once("exit",(()=>{e()}))}));s.once("disconnect",(()=>{s.kill()})),await this.sendKillMessageToWorker(e),t.removeAllListeners(),s.disconnect(),await r}sendToWorker(e,t){this.workerNodes[e].worker.send({...t,workerId:this.getWorkerInfo(e).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 r.fork(this.opts.env)}get type(){return k.fixed}get worker(){return c.cluster}get busy(){return this.internalBusy()}}class Y extends ${opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}isMain(){return i.isMainThread}async destroyWorkerNode(e){this.flagWorkerNodeAsNotReady(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(),t.removeAllListeners(),await s.terminate(),await r}sendToWorker(e,t,s){this.workerNodes[e].messageChannel?.port1?.postMessage({...t,workerId:this.getWorkerInfo(e).id},s)}sendStartupMessageToWorker(e){const t=this.workerNodes[e],s=t.messageChannel.port2;t.worker.postMessage({ready:!1,workerId:this.getWorkerInfo(e).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 i.Worker(this.filePath,{env:i.SHARE_ENV,...this.opts.workerOptions})}get type(){return k.fixed}get worker(){return c.thread}get busy(){return this.internalBusy()}}const J=(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")},X=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")},Z=6e4,ee={killBehavior:M.SOFT,maxInactiveTime:Z,killHandler:g};class te{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,s,r=ee){if(this.isMain=e,this.mainWorker=t,this.opts=r,null==this.isMain)throw new Error("isMain parameter is mandatory");this.checkTaskFunctions(s),this.checkWorkerOptions(this.opts),this.isMain||this.getMainWorker().on("message",this.handleReadyMessage.bind(this))}checkWorkerOptions(e){(e=>{if(null!=e&&!W(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")})(e),this.opts={...ee,...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(l,t),this.taskFunctions.set("string"==typeof e.name&&e.name.trim().length>0?e.name:"fn1",t)}else{if(!W(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)){J(s,r);const e=r.bind(this);t&&(this.taskFunctions.set(l,e),t=!1),this.taskFunctions.set(s,e)}if(t)throw new Error("taskFunctions parameter object is empty")}}}hasTaskFunction(e){try{X(e)}catch(e){return{status:!1,error:e}}return{status:this.taskFunctions.has(e)}}addTaskFunction(e,t){try{if(X(e),e===l)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(l)&&this.taskFunctions.set(l,s),this.taskFunctions.set(e,s),this.sendTaskFunctionNamesToMainWorker(),{status:!0}}catch(e){return{status:!1,error:e}}}removeTaskFunction(e){try{if(X(e),e===l)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(l))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=l;for(const[e,s]of this.taskFunctions)if(e!==l&&s===this.taskFunctions.get(l)){t=e;break}return[e[e.indexOf(l)],t,...e.filter((e=>e!==l&&e!==t))]}setDefaultTaskFunction(e){try{if(X(e),e===l)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(l,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(),x(this.opts.killHandler))(this.opts.killHandler?.()).then((()=>{this.sendToMainWorker({kill:"success"})})).catch((()=>{this.sendToMainWorker({kill:"failure"})}));else try{this.opts.killHandler?.(),this.sendToMainWorker({kill:"success"})}catch{this.sendToMainWorker({kill:"failure"})}}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Message worker id is not set");if(e.workerId!==this.id)throw new Error(`Message worker id ${e.workerId} does not match the worker id ${this.id}`)}startCheckActive(){this.lastTaskTimestamp=o.performance.now(),this.activeInterval=setInterval(this.checkActive.bind(this),(this.opts.maxInactiveTime??Z)/2)}stopCheckActive(){null!=this.activeInterval&&(clearInterval(this.activeInterval),delete this.activeInterval)}checkActive(){o.performance.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??Z)&&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=t??l;if(!this.taskFunctions.has(i))return void this.sendToMainWorker({workerError:{name:t,message:`Task function '${t}' not found`,data:r},taskId:s});const o=this.taskFunctions.get(i);x(o)?this.runAsync(o,e):this.runSync(o,e)};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(g)};beginTaskPerformance(e){return this.checkStatistics(),{name:e??l,timestamp:o.performance.now(),...this.statistics.elu&&{elu:o.performance.eventLoopUtilization()}}}endTaskPerformance(e){return this.checkStatistics(),{...e,...this.statistics.runTime&&{runTime:o.performance.now()-e.timestamp},...this.statistics.elu&&{elu:o.performance.eventLoopUtilization(e.elu)}}}checkStatistics(){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set")}updateLastTaskTimestamp(){null!=this.activeInterval&&(this.lastTaskTimestamp=o.performance.now())}}exports.ClusterWorker=class extends te{constructor(e,t={}){super(r.isPrimary,r.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 G{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,R(this.numberOfWorkers,this.max)}get type(){return k.dynamic}get busy(){return this.full&&this.internalBusy()}},exports.DynamicThreadPool=class extends Y{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,R(this.numberOfWorkers,this.max)}get type(){return k.dynamic}get busy(){return this.full&&this.internalBusy()}},exports.FixedClusterPool=G,exports.FixedThreadPool=Y,exports.KillBehaviors=M,exports.Measurements=b,exports.PoolEvents=d,exports.PoolTypes=k,exports.ThreadWorker=class extends te{port;constructor(e,t={}){super(i.isMainThread,i.parentPort,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 i.threadId}sendToMainWorker=e=>{this.port?.postMessage({...e,workerId:this.id})};handleError(e){return e}},exports.WorkerChoiceStrategies=F,exports.WorkerTypes=c,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:cluster"),t=require("node:fs"),s=require("node:worker_threads"),r=require("node:os"),i=require("node:crypto"),o=require("node:perf_hooks"),n=require("node:events"),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"}),d=Object.freeze({ready:"ready",busy:"busy",full:"full",destroy:"destroy",error:"error",taskError:"taskError",backPressure:"backPressure"}),c=Object.freeze({thread:"thread",cluster:"cluster"}),l="default",g=Object.freeze((()=>{})),m={retries:6,runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},p={aggregate:!1,average:!1,median:!1},w=t=>t instanceof s.Worker?c.thread:t instanceof e.Worker?c.cluster:void 0,y=t=>t instanceof s.Worker?t.threadId:t instanceof e.Worker?t.id:void 0,T=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,f=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},W=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),S=(e,t)=>t===e,v=e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name,x=()=>i.getRandomValues(new Uint32Array(1))[0]/4294967296,E=(...e)=>e.reduce(((e,t)=>e<t?e:t),1/0),I=(...e)=>e.reduce(((e,t)=>e>t?e:t),-1/0),b=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"}),F=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"}),O=e=>{if(null==e)throw new TypeError("The worker file path must be specified");if("string"!=typeof e)throw new TypeError("The worker file path must be a string");if(!t.existsSync(e))throw new Error(`Cannot find the worker file '${e}'`)},R=(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")},C=e=>{if(null!=e&&!Object.values(b).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)},z=e=>{if(null!=e&&!W(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=E(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=T(e.history):null!=e.average&&delete e.average,t.median?e.median=f(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:p,waitTime:p,elu:p};constructor(e,t=m){this.pool=e,this.opts=t,this.opts={...m,...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={...m,...e},this.setTaskStatisticsRequirements(this.opts)}hasPoolWorkerNodesReady(){return this.pool.workerNodes.some((e=>e.info.ready))}isWorkerNodeReady(e){return this.pool.workerNodes[e]?.info?.ready??!1}checkNextWorkerNodeReadiness(){this.isWorkerNodeReady(this.nextWorkerNodeKey)||delete this.nextWorkerNodeKey}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}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:p,elu:{aggregate:!0,average:!0,median:!1}};constructor(e,t=m){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)}),this.isWorkerNodeReady(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===F.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 U extends q{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:p,elu:p};roundId=0;defaultWorkerWeight;roundWeights;workerNodeId=0;workerNodeVirtualTaskRunTime=0;constructor(e,t=m){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(this.isWorkerNodeReady(t)&&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 Q extends q{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:p};constructor(e,t=m){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)=>this.isWorkerNodeReady(s)&&(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 A extends q{constructor(e,t=m){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)=>this.isWorkerNodeReady(s)&&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 B extends q{taskStatisticsRequirements={runTime:p,waitTime:p,elu:{aggregate:!0,average:!1,median:!1}};constructor(e,t=m){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)=>this.isWorkerNodeReady(s)&&(t.usage.elu.active.aggregate??0)<(r[e].usage.elu.active.aggregate??0)?s:e),0)}}class D extends q{constructor(e,t=m){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(),this.checkNextWorkerNodeReadiness(),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:p,elu:p};defaultWorkerWeight;workerNodeVirtualTaskRunTime=0;constructor(e,t=m){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(),this.checkNextWorkerNodeReadiness(),this.nextWorkerNodeKey}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 H{workerChoiceStrategy;opts;workerChoiceStrategies;constructor(e,t=b.ROUND_ROBIN,s=m){this.workerChoiceStrategy=t,this.opts=s,this.opts={...m,...s},this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[b.ROUND_ROBIN,new(D.bind(this))(e,s)],[b.LEAST_USED,new(A.bind(this))(e,s)],[b.LEAST_BUSY,new(Q.bind(this))(e,s)],[b.LEAST_ELU,new(B.bind(this))(e,s)],[b.FAIR_SHARE,new(K.bind(this))(e,s)],[b.WEIGHTED_ROUND_ROBIN,new(L.bind(this))(e,s)],[b.INTERLEAVED_WEIGHTED_ROUND_ROBIN,new(U.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);let t;const s=1e4;let r=0,i=0,o=0;do{e.hasPoolWorkerNodesReady()&&(t=e.choose(),i>0&&o++,i++),r++}while(r<s&&(!e.hasPoolWorkerNodesReady()||null==t&&o<this.opts.retries));if(r>=s)throw new RangeError("Worker choice strategy consecutive executions has exceeded the maximum of 10000");if(null==t)throw new Error(`Worker node key chosen is null or undefined after ${o} retries`);return t}remove(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).remove(e)}setOptions(e){this.opts={...m,...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 _{data;next;prev;constructor(e){this.data=e}}class V{head;tail;size;maxSize;constructor(){this.clear()}push(e){const t=new _(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 _(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?delete this.head:delete this.tail.next,--this.size,e?.data}shift(){if(null==this.head)return;const e=this.head;return this.head=this.head.next,null==this.head?delete this.tail:delete this.head.prev,--this.size,e?.data}peekFirst(){return this.head?.data}peekLast(){return this.tail?.data}clear(){delete this.head,delete this.tail,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 $ extends n.EventEmitter{worker;info;usage;strategyData;messageChannel;tasksQueueBackPressureSize;tasksQueue;onBackPressureStarted;taskFunctionsUsage;constructor(t,r,i){super(),((e,t,s)=>{if(null==e)throw new TypeError("Cannot construct a worker node without a worker type");if(!Object.values(c).includes(e))throw new TypeError(`Cannot construct a worker node with an invalid worker type '${e}'`);if(O(t),null==s)throw new TypeError("Cannot construct a worker node without worker node options");if(!W(s))throw new TypeError("Cannot construct a worker node with invalid options: must be a plain object");if(null==s.tasksQueueBackPressureSize)throw new TypeError("Cannot construct a worker node without a tasks queue back pressure size option");if(!Number.isSafeInteger(s.tasksQueueBackPressureSize))throw new TypeError("Cannot construct a worker node with a tasks queue back pressure size option that is not an integer");if(s.tasksQueueBackPressureSize<=0)throw new RangeError("Cannot construct a worker node with a tasks queue back pressure size option that is not a positive integer")})(t,r,i),this.worker=((t,r,i)=>{switch(t){case c.thread:return new s.Worker(r,{env:s.SHARE_ENV,...i?.workerOptions});case c.cluster:return e.fork(i?.env);default:throw new Error(`Unknown worker type '${t}'`)}})(t,r,{env:i.env,workerOptions:i.workerOptions}),this.info=this.initWorkerInfo(this.worker),this.usage=this.initWorkerUsage(),this.info.type===c.thread&&(this.messageChannel=new s.MessageChannel),this.tasksQueueBackPressureSize=i.tasksQueueBackPressureSize,this.tasksQueue=new V,this.onBackPressureStarted=!1,this.taskFunctionsUsage=new Map}tasksQueueSize(){return this.tasksQueue.size}enqueueTask(e){const t=this.tasksQueue.push(e);return this.hasBackPressure()&&!this.onBackPressureStarted&&(this.onBackPressureStarted=!0,this.emit("backPressure",{workerId:this.info.id}),this.onBackPressureStarted=!1),t}unshiftTask(e){const t=this.tasksQueue.unshift(e);return this.hasBackPressure()&&!this.onBackPressureStarted&&(this.onBackPressureStarted=!0,this.emit("backPressure",{workerId:this.info.id}),this.onBackPressureStarted=!1),t}dequeueTask(){return this.tasksQueue.shift()}popTask(){return this.tasksQueue.pop()}clearTasksQueue(){this.tasksQueue.clear()}hasBackPressure(){return this.tasksQueue.size>=this.tasksQueueBackPressureSize}resetUsage(){this.usage=this.initWorkerUsage(),this.taskFunctionsUsage.clear()}async terminate(){const e=new Promise((e=>{this.registerOnceWorkerEventHandler("exit",(()=>{e()}))}));this.closeMessageChannel(),this.removeAllListeners(),this.info.type===c.thread?await(this.worker.terminate?.()):this.info.type===c.cluster&&(this.registerOnceWorkerEventHandler("disconnect",(()=>{this.worker.kill?.()})),this.worker.disconnect?.()),await e}registerWorkerEventHandler(e,t){this.worker.on(e,t)}registerOnceWorkerEventHandler(e,t){this.worker.once(e,t)}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===l&&(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)}closeMessageChannel(){null!=this.messageChannel&&(this.messageChannel.port1.unref(),this.messageChannel.port2.unref(),this.messageChannel.port1.close(),this.messageChannel.port2.close(),delete this.messageChannel)}initWorkerInfo(e){return{id:y(e),type:w(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()},sequentiallyStolen:0,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===l&&e===this.info.taskFunctionNames[1]||s.name!==l&&e===s.name)&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},sequentiallyStolen:0,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;max;promiseResponseMap=new Map;workerChoiceStrategyContext;taskFunctions;started;starting;destroying;readyEventEmitted;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");O(this.filePath),this.checkNumberOfWorkers(this.numberOfWorkers),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.initializeEventEmitter(),this.workerChoiceStrategyContext=new H(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook(),this.taskFunctions=new Map,this.started=!1,this.starting=!1,this.destroying=!1,this.readyEventEmitted=!1,!0===this.opts.startWorkers&&this.start(),this.startTimestamp=o.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(!W(e))throw new TypeError("Invalid pool options: must be a plain object");this.opts.startWorkers=e.startWorkers??!0,C(e.workerChoiceStrategy),this.opts.workerChoiceStrategy=e.workerChoiceStrategy??b.ROUND_ROBIN,this.checkValidWorkerChoiceStrategyOptions(e.workerChoiceStrategyOptions),this.opts.workerChoiceStrategyOptions={...m,...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&&!W(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(F).includes(e.measurement))throw new Error(`Invalid worker choice strategy options: invalid measurement '${e.measurement}'`)}initializeEventEmitter(){this.emitter=new n.EventEmitterAsyncResource({name:`poolifier:${this.type}-${this.worker}-pool`})}get info(){return{version:"3.1.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: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,s)=>this.isWorkerNodeBusy(s)?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(E(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:N(I(...this.workerNodes.map((e=>e.usage.runTime?.maximum??-1/0)))),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.average&&{average:N(T(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&{median:N(f(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:N(E(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:N(I(...this.workerNodes.map((e=>e.usage.waitTime?.maximum??-1/0)))),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.average&&{average:N(T(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.waitTime.history)),[])))},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&{median:N(f(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=(o.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(-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){C(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={...m,...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.unsetTaskStealing(),this.setTaskStealing()):this.unsetTaskStealing(),!0===this.opts.tasksQueueOptions.tasksStealingOnBackPressure?(this.unsetTasksStealingOnBackPressure(),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].on("idleWorkerNode",this.handleIdleWorkerNodeEvent)}unsetTaskStealing(){for(const[e]of this.workerNodes.entries())this.workerNodes[e].off("idleWorkerNode",this.handleIdleWorkerNodeEvent)}setTasksStealingOnBackPressure(){for(const[e]of this.workerNodes.entries())this.workerNodes[e].on("backPressure",this.handleBackPressureEvent)}unsetTasksStealingOnBackPressure(){for(const[e]of this.workerNodes.entries())this.workerNodes[e].off("backPressure",this.handleBackPressureEvent)}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))}isWorkerNodeBusy(e){return!0===this.opts.enableTasksQueue?this.workerNodes[e].usage.tasks.executing>=this.opts.tasksQueueOptions?.concurrency:this.workerNodes[e].usage.tasks.executing>0}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,n)=>{if(!this.started)return void n(new Error("Cannot execute a task on not started pool"));if(this.destroying)return void n(new Error("Cannot execute a task on destroying pool"));if(null!=t&&"string"!=typeof t)return void n(new TypeError("name argument must be a string"));if(null!=t&&"string"==typeof t&&0===t.trim().length)return void n(new TypeError("name argument must not be an empty string"));if(null!=s&&!Array.isArray(s))return void n(new TypeError("transferList argument must be an array"));const u=o.performance.now(),h=this.chooseWorkerNode(),k={name:t??l,data:e??{},transferList:s,timestamp:u,taskId:i.randomUUID()};this.promiseResponseMap.set(k.taskId,{resolve:r,reject:n,workerNodeKey:h,...null!=this.emitter&&{asyncResource:new a.AsyncResource("poolifier:task",{triggerAsyncId:this.emitter.asyncId,requireManualDestroy:!0})}}),!1===this.opts.enableTasksQueue||!0===this.opts.enableTasksQueue&&this.shallExecuteTask(h)?this.executeTask(h,k):this.enqueueTask(h,k)}))}start(){if(this.started)throw new Error("Cannot start an already started pool");if(this.starting)throw new Error("Cannot start an already starting pool");if(this.destroying)throw new Error("Cannot start a destroying pool");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(){if(!this.started)throw new Error("Cannot destroy an already destroyed pool");if(this.starting)throw new Error("Cannot destroy an starting pool");if(this.destroying)throw new Error("Cannot destroy an already destroying pool");this.destroying=!0,await Promise.all(this.workerNodes.map((async(e,t)=>{await this.destroyWorkerNode(t)}))),this.emitter?.emit(d.destroy,this.info),this.emitter?.emitDestroy(),this.emitter?.removeAllListeners(),this.readyEventEmitted=!1,this.destroying=!1,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})}))}async destroyWorkerNode(e){this.flagWorkerNodeAsNotReady(e),this.flushTasksQueue(e);const t=this.workerNodes[e];await this.sendKillMessageToWorker(e),await t.terminate()}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=o.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.createWorkerNode();e.registerWorkerEventHandler("online",this.opts.onlineHandler??g),e.registerWorkerEventHandler("message",this.opts.messageHandler??g),e.registerWorkerEventHandler("error",this.opts.errorHandler??g),e.registerWorkerEventHandler("error",(t=>{e.info.ready=!1,this.emitter?.emit(d.error,t),!this.started||this.starting||this.destroying||!0!==this.opts.restartWorkerOnError||(e.info.dynamic?this.createAndSetupDynamicWorkerNode():this.createAndSetupWorkerNode()),this.started&&!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(this.workerNodes.indexOf(e)),e.terminate().catch((e=>{this.emitter?.emit(d.error,e)}))})),e.registerWorkerEventHandler("exit",this.opts.exitHandler??g),e.registerOnceWorkerEventHandler("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;(S(M.HARD,e.kill)||S(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.flagWorkerNodeAsNotReady(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.workerMessageListener),this.sendStartupMessageToWorker(e),this.sendStatisticsMessageToWorker(e),!0===this.opts.enableTasksQueue&&(!0===this.opts.tasksQueueOptions?.taskStealing&&this.workerNodes[e].on("idleWorkerNode",this.handleIdleWorkerNodeEvent),!0===this.opts.tasksQueueOptions?.tasksStealingOnBackPressure&&this.workerNodes[e].on("backPressure",this.handleBackPressureEvent))}sendStatisticsMessageToWorker(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate}})}handleTask(e,t){this.shallExecuteTask(e)?this.executeTask(e,t):this.enqueueTask(e,t)}redistributeQueuedTasks(e){if(!(this.workerNodes.length<=1))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);this.handleTask(t,this.dequeueTask(e))}}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}}updateTaskSequentiallyStolenStatisticsWorkerUsage(e){const t=this.workerNodes[e];null!=t?.usage&&++t.usage.tasks.sequentiallyStolen}updateTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(e,t){const s=this.workerNodes[e];if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=s.getTaskFunctionWorkerUsage(t)){++s.getTaskFunctionWorkerUsage(t).tasks.sequentiallyStolen}}resetTaskSequentiallyStolenStatisticsWorkerUsage(e){const t=this.workerNodes[e];null!=t?.usage&&(t.usage.tasks.sequentiallyStolen=0)}resetTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(e,t){const s=this.workerNodes[e];if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=s.getTaskFunctionWorkerUsage(t)){s.getTaskFunctionWorkerUsage(t).tasks.sequentiallyStolen=0}}handleIdleWorkerNodeEvent=(e,t)=>{if(this.workerNodes.length<=1)return;const{workerNodeKey:s}=e;if(null==s)throw new Error("WorkerNode event detail workerNodeKey attribute must be defined");const r=this.workerNodes[s].usage.tasks;if(null!=t&&r.sequentiallyStolen>0&&(r.executing>0||this.tasksQueueSize(s)>0)){for(const e of this.workerNodes[s].info.taskFunctionNames)this.resetTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(s,e);return void this.resetTaskSequentiallyStolenStatisticsWorkerUsage(s)}const i=this.workerNodeStealTask(s);if(this.shallUpdateTaskFunctionWorkerUsage(s)&&null!=i){const e=this.workerNodes[s].getTaskFunctionWorkerUsage(i.name)?.tasks;0===e.sequentiallyStolen||null!=t&&t.name===i.name&&e.sequentiallyStolen>0?this.updateTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(s,i.name):this.resetTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(s,i.name)}(async e=>{await new Promise((t=>{setTimeout(t,e)}))})(((e=0,t=100)=>{const s=Math.pow(2,e)*t;return s+.2*s*x()})(r.sequentiallyStolen)).then((()=>{this.handleIdleWorkerNodeEvent(e,i)})).catch(g)};workerNodeStealTask=e=>{const t=this.workerNodes.slice().sort(((e,t)=>t.usage.tasks.queued-e.usage.tasks.queued)).find(((t,s)=>t.info.ready&&s!==e&&t.usage.tasks.queued>0));if(null!=t){const s=t.popTask();return this.handleTask(e,s),this.updateTaskSequentiallyStolenStatisticsWorkerUsage(e),this.updateTaskStolenStatisticsWorkerUsage(e,s.name),s}};handleBackPressureEvent=e=>{if(this.workerNodes.length<=1)return;const{workerId:t}=e;if(this.opts.tasksQueueOptions?.size<=1)return;const s=this.workerNodes[this.getWorkerNodeKeyByWorkerId(t)],r=this.workerNodes.slice().sort(((e,t)=>e.usage.tasks.queued-t.usage.tasks.queued));for(const[e,i]of r.entries())if(s.usage.tasks.queued>0&&i.info.ready&&i.info.id!==t&&i.usage.tasks.queued<this.opts.tasksQueueOptions?.size-1){const t=s.popTask();this.handleTask(e,t),this.updateTaskStolenStatisticsWorkerUsage(e,t.name)}};workerMessageListener=e=>{this.checkMessageWorkerId(e);const{workerId:t,ready:s,taskId:r,taskFunctionNames:i}=e;null!=s&&null!=i?this.handleWorkerReadyResponse(e):null!=r?this.handleTaskExecutionResponse(e):null!=i&&(this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(t)).taskFunctionNames=i)};handleWorkerReadyResponse(e){const{workerId:t,ready:s,taskFunctionNames:r}=e;if(!1===s)throw new Error(`Worker ${t} failed to initialize`);const i=this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(t));i.ready=s,i.taskFunctionNames=r,!this.readyEventEmitted&&this.ready&&(this.readyEventEmitted=!0,this.emitter?.emit(d.ready,this.info))}handleTaskExecutionResponse(e){const{workerId:t,taskId:s,workerError:r,data:i}=e,o=this.promiseResponseMap.get(s);if(null!=o){const{resolve:n,reject:a,workerNodeKey:u,asyncResource:h}=o;if(null!=r?(this.emitter?.emit(d.taskError,r),null!=h?h.runInAsyncScope(a,this.emitter,r.message):a(r.message)):null!=h?h.runInAsyncScope(n,this.emitter,i):n(i),h?.emitDestroy(),this.afterTaskExecutionHook(u,e),this.workerChoiceStrategyContext.update(u),this.promiseResponseMap.delete(s),!0===this.opts.enableTasksQueue){const e=this.workerNodes[u].usage.tasks;this.tasksQueueSize(u)>0&&e.executing<this.opts.tasksQueueOptions?.concurrency&&this.executeTask(u,this.dequeueTask(u)),0===e.executing&&0===this.tasksQueueSize(u)&&0===e.sequentiallyStolen&&this.workerNodes[u].emit("idleWorkerNode",{workerId:t,workerNodeKey:u})}}}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}createWorkerNode(){const e=new $(this.worker,this.filePath,{env:this.opts.env,workerOptions:this.opts.workerOptions,tasksQueueBackPressureSize:this.opts.tasksQueueOptions?.size??Math.pow(this.maxSize,2)});return this.starting&&(e.info.ready=!0),e}addWorkerNode(e){this.workerNodes.push(e);const t=this.workerNodes.indexOf(e);if(-1===t)throw new Error("Worker added not found in worker nodes");return t}removeWorkerNode(e){const t=this.workerNodes.indexOf(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategyContext.remove(t))}flagWorkerNodeAsNotReady(e){this.getWorkerInfo(e).ready=!1}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(){e.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return e.isPrimary}sendToWorker(e,t){this.workerNodes[e].worker.send({...t,workerId:this.getWorkerInfo(e).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)}get type(){return k.fixed}get worker(){return c.cluster}get busy(){return this.internalBusy()}}class J extends G{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}isMain(){return s.isMainThread}sendToWorker(e,t,s){this.workerNodes[e].messageChannel?.port1?.postMessage({...t,workerId:this.getWorkerInfo(e).id},s)}sendStartupMessageToWorker(e){const t=this.workerNodes[e],s=t.messageChannel.port2;t.worker.postMessage({ready:!1,workerId:this.getWorkerInfo(e).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)}get type(){return k.fixed}get worker(){return c.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:g};class se{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,s,r=te){if(this.isMain=e,this.mainWorker=t,this.opts=r,null==this.isMain)throw new Error("isMain parameter is mandatory");this.checkTaskFunctions(s),this.checkWorkerOptions(this.opts),this.isMain||this.getMainWorker().on("message",this.handleReadyMessage.bind(this))}checkWorkerOptions(e){(e=>{if(null!=e&&!W(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")})(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(l,t),this.taskFunctions.set("string"==typeof e.name&&e.name.trim().length>0?e.name:"fn1",t)}else{if(!W(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(l,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===l)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(l)&&this.taskFunctions.set(l,s),this.taskFunctions.set(e,s),this.sendTaskFunctionNamesToMainWorker(),{status:!0}}catch(e){return{status:!1,error:e}}}removeTaskFunction(e){try{if(Z(e),e===l)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(l))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=l;for(const[e,s]of this.taskFunctions)if(e!==l&&s===this.taskFunctions.get(l)){t=e;break}return[e[e.indexOf(l)],t,...e.filter((e=>e!==l&&e!==t))]}setDefaultTaskFunction(e){try{if(Z(e),e===l)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(l,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(),v(this.opts.killHandler))(this.opts.killHandler?.()).then((()=>{this.sendToMainWorker({kill:"success"})})).catch((()=>{this.sendToMainWorker({kill:"failure"})}));else try{this.opts.killHandler?.(),this.sendToMainWorker({kill:"success"})}catch{this.sendToMainWorker({kill:"failure"})}}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Message worker id is not set");if(e.workerId!==this.id)throw new Error(`Message worker id ${e.workerId} does not match the worker id ${this.id}`)}startCheckActive(){this.lastTaskTimestamp=o.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(){o.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=t??l;if(!this.taskFunctions.has(i))return void this.sendToMainWorker({workerError:{name:t,message:`Task function '${t}' not found`,data:r},taskId:s});const o=this.taskFunctions.get(i);v(o)?this.runAsync(o,e):this.runSync(o,e)};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(g)};beginTaskPerformance(e){return this.checkStatistics(),{name:e??l,timestamp:o.performance.now(),...this.statistics.elu&&{elu:o.performance.eventLoopUtilization()}}}endTaskPerformance(e){return this.checkStatistics(),{...e,...this.statistics.runTime&&{runTime:o.performance.now()-e.timestamp},...this.statistics.elu&&{elu:o.performance.eventLoopUtilization(e.elu)}}}checkStatistics(){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set")}updateLastTaskTimestamp(){null!=this.activeInterval&&(this.lastTaskTimestamp=o.performance.now())}}exports.ClusterWorker=class extends se{constructor(t,s={}){super(e.isPrimary,e.worker,t,s)}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,R(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,R(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=F,exports.PoolEvents=d,exports.PoolTypes=k,exports.ThreadWorker=class extends se{port;constructor(e,t={}){super(s.isMainThread,s.parentPort,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 s.threadId}sendToMainWorker=e=>{this.port?.postMessage({...e,workerId:this.id})};handleError(e){return e}},exports.WorkerChoiceStrategies=b,exports.WorkerTypes=c,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};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|