poolifier 2.6.36 → 2.6.37

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/deque.d.ts CHANGED
@@ -1,17 +1,20 @@
1
1
  /**
2
+ * Node.
3
+ *
4
+ * @typeParam T - Type of node data.
2
5
  * @internal
3
6
  */
4
7
  export declare class Node<T> {
5
- value: T;
8
+ data: T;
6
9
  next?: Node<T>;
7
10
  prev?: Node<T>;
8
- constructor(value: T);
11
+ constructor(data: T);
9
12
  }
10
13
  /**
11
14
  * Deque.
12
15
  * Implemented with a doubly linked list.
13
16
  *
14
- * @typeParam T - Type of deque values.
17
+ * @typeParam T - Type of deque data.
15
18
  * @internal
16
19
  */
17
20
  export declare class Deque<T> {
@@ -23,39 +26,39 @@ export declare class Deque<T> {
23
26
  maxSize: number;
24
27
  constructor();
25
28
  /**
26
- * Appends a value to the deque.
29
+ * Appends data to the deque.
27
30
  *
28
- * @param value - Value to append.
31
+ * @param data - Data to append.
29
32
  * @returns The new size of the queue.
30
33
  */
31
- push(value: T): number;
34
+ push(data: T): number;
32
35
  /**
33
- * Prepends a value to the deque.
36
+ * Prepends data to the deque.
34
37
  *
35
- * @param value - Value to prepend.
38
+ * @param data - Data to prepend.
36
39
  * @returns The new size of the queue.
37
40
  */
38
- unshift(value: T): number;
41
+ unshift(data: T): number;
39
42
  /**
40
- * Pops a value from the deque.
43
+ * Pops data from the deque.
41
44
  *
42
- * @returns The popped value or `undefined` if the deque is empty.
45
+ * @returns The popped data or `undefined` if the deque is empty.
43
46
  */
44
47
  pop(): T | undefined;
45
48
  /**
46
- * Shifts a value from the deque.
49
+ * Shifts data from the deque.
47
50
  *
48
- * @returns The shifted value or `undefined` if the deque is empty.
51
+ * @returns The shifted data or `undefined` if the deque is empty.
49
52
  */
50
53
  shift(): T | undefined;
51
54
  /**
52
- * Peeks at the first value.
53
- * @returns The first value or `undefined` if the deque is empty.
55
+ * Peeks at the first data.
56
+ * @returns The first data or `undefined` if the deque is empty.
54
57
  */
55
58
  peekFirst(): T | undefined;
56
59
  /**
57
- * Peeks at the last value.
58
- * @returns The last value or `undefined` if the deque is empty.
60
+ * Peeks at the last data.
61
+ * @returns The last data or `undefined` if the deque is empty.
59
62
  */
60
63
  peekLast(): T | undefined;
61
64
  /**
package/lib/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export { FixedClusterPool, type ClusterPoolOptions } from './pools/cluster/fixed
4
4
  export { PoolEvents, PoolTypes } from './pools/pool';
5
5
  export type { IPool, PoolEmitter, PoolEvent, PoolInfo, PoolOptions, PoolType, TasksQueueOptions } from './pools/pool';
6
6
  export { WorkerTypes } from './pools/worker';
7
- export type { ErrorHandler, EventLoopUtilizationMeasurementStatistics, ExitHandler, IWorker, IWorkerNode, MeasurementStatistics, MessageHandler, OnlineHandler, TaskStatistics, WorkerInfo, WorkerType, WorkerUsage } from './pools/worker';
7
+ export type { ErrorHandler, EventLoopUtilizationMeasurementStatistics, ExitHandler, IWorker, IWorkerNode, MeasurementStatistics, MessageHandler, OnlineHandler, TaskStatistics, WorkerInfo, WorkerNodeEventCallback, WorkerType, WorkerUsage } from './pools/worker';
8
8
  export { Measurements, WorkerChoiceStrategies } from './pools/selection-strategies/selection-strategies-types';
9
9
  export type { IWorkerChoiceStrategy, Measurement, MeasurementOptions, MeasurementStatisticsRequirements, StrategyPolicy, TaskStatisticsRequirements, WorkerChoiceStrategy, WorkerChoiceStrategyOptions } from './pools/selection-strategies/selection-strategies-types';
10
10
  export type { WorkerChoiceStrategyContext } from './pools/selection-strategies/worker-choice-strategy-context';
package/lib/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var e=require("node:events"),t=require("node:worker_threads"),s=require("node:cluster"),r=require("node:crypto"),i=require("node:perf_hooks"),o=require("node:fs"),n=require("node:os"),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(n);const k=Object.freeze({fixed:"fixed",dynamic:"dynamic"});class c extends e.EventEmitter{}const d=Object.freeze({ready:"ready",busy:"busy",full:"full",destroy:"destroy",error:"error",taskError:"taskError",backPressure:"backPressure"}),l="default",g=Object.freeze((()=>{})),m={choiceRetries:6,runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},p={aggregate:!1,average:!1,median:!1},w=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,y=e=>{if(Array.isArray(e)&&0===e.length)return 0;if(Array.isArray(e)&&1===e.length)return e[0];const t=e.slice().sort(((e,t)=>e-t));return(t[t.length-1>>1]+t[t.length>>1])/2},f=(e,t=2)=>{const s=Math.pow(10,t);return Math.round(e*s*(1+Number.EPSILON))/s},T=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),W=(e,t)=>t===e,N=e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name,x=(e,t,s)=>{t.aggregate&&(e.aggregate=(e.aggregate??0)+s,e.minimum=Math.min(s,e.minimum??1/0),e.maximum=Math.max(s,e.maximum??-1/0),(t.average||t.median)&&null!=s&&(e.history.push(s),t.average&&(e.average=w(e.history)),t.median&&(e.median=y(e.history))))},S=()=>r.webcrypto.getRandomValues(new Uint32Array(1))[0]/4294967296,E=Object.freeze({SOFT:"SOFT",HARD:"HARD"}),v=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"});class I{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)}isWorkerNodeReady(e){return this.pool.workerNodes[e].info.ready}hasWorkerNodeBackPressure(e){return this.pool.hasWorkerNodeBackPressure(e)}isWorkerNodeEligible(e){return this.isWorkerNodeReady(e)&&!this.hasWorkerNodeBackPressure(e)}getWorkerTaskRunTime(e){return this.taskStatisticsRequirements.runTime.median?this.pool.workerNodes[e].usage.runTime?.median??0:this.pool.workerNodes[e].usage.runTime?.average??0}getWorkerTaskWaitTime(e){return this.taskStatisticsRequirements.waitTime.median?this.pool.workerNodes[e].usage.waitTime?.median??0:this.pool.workerNodes[e].usage.waitTime?.average??0}getWorkerTaskElu(e){return this.taskStatisticsRequirements.elu.median?this.pool.workerNodes[e].usage.elu.active?.median??0:this.pool.workerNodes[e].usage.elu.active?.average??0}checkNextWorkerNodeEligibility(e){this.isWorkerNodeEligible(this.nextWorkerNodeKey)||(this.nextWorkerNodeKey=void 0,this.previousWorkerNodeKey=e??this.previousWorkerNodeKey)}computeDefaultWorkerWeight(){let e=0;for(const t of n.cpus()){const s=t.speed.toString().length-1;e+=1/(t.speed/Math.pow(10,s))*Math.pow(10,s)}return Math.round(e/n.cpus().length)}}class C extends I{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:p,elu:{aggregate:!0,average:!0,median:!1}};workersVirtualTaskEndTimestamp=[];constructor(e,t=m){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.workersVirtualTaskEndTimestamp=[],!0}update(e){return this.computeWorkerVirtualTaskEndTimestamp(e),!0}choose(){return this.nextWorkerNodeKey=this.fairShareNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(e){return this.workersVirtualTaskEndTimestamp.splice(e,1),!0}fairShareNextWorkerNodeKey(){let e,t=1/0;for(const[s]of this.pool.workerNodes.entries()){null==this.workersVirtualTaskEndTimestamp[s]&&this.computeWorkerVirtualTaskEndTimestamp(s);const r=this.workersVirtualTaskEndTimestamp[s];this.isWorkerNodeEligible(s)&&r<t&&(t=r,e=s)}return e}computeWorkerVirtualTaskEndTimestamp(e){this.workersVirtualTaskEndTimestamp[e]=this.getWorkerVirtualTaskEndTimestamp(e,this.getWorkerVirtualTaskStartTimestamp(e))}getWorkerVirtualTaskEndTimestamp(e,t){return t+(this.opts.measurement===b.elu?this.getWorkerTaskElu(e):this.getWorkerTaskRunTime(e))}getWorkerVirtualTaskStartTimestamp(e){return Math.max(performance.now(),this.workersVirtualTaskEndTimestamp[e]??-1/0)}}class R extends I{roundId=0;roundWeights;defaultWorkerWeight;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,!0}update(){return!0}choose(){let e,t;for(let s=this.roundId;s<this.roundWeights.length;s++){e=s;for(let e=this.nextWorkerNodeKey??this.previousWorkerNodeKey;e<this.pool.workerNodes.length;e++){const r=this.opts.weights?.[e]??this.defaultWorkerWeight;if(this.isWorkerNodeEligible(e)&&r>=this.roundWeights[s]){t=e;break}}}this.roundId=e,null==t&&(this.previousWorkerNodeKey=this.nextWorkerNodeKey??this.previousWorkerNodeKey),this.nextWorkerNodeKey=t;const s=this.nextWorkerNodeKey;return this.nextWorkerNodeKey===this.pool.workerNodes.length-1?(this.nextWorkerNodeKey=0,this.roundId=this.roundId===this.roundWeights.length-1?0:this.roundId+1):this.nextWorkerNodeKey=(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,s}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1,this.roundId=this.roundId===this.roundWeights.length-1?0:this.roundId+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 z extends I{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.nextWorkerNodeKey=this.leastBusyNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastBusyNextWorkerNodeKey(){let e,t=1/0;for(const[s,r]of this.pool.workerNodes.entries()){const i=(r.usage.runTime?.aggregate??0)+(r.usage.waitTime?.aggregate??0);if(this.isWorkerNodeEligible(s)&&0===i){e=s;break}this.isWorkerNodeEligible(s)&&i<t&&(t=i,e=s)}return e}}class O extends I{constructor(e,t=m){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.nextWorkerNodeKey=this.leastUsedNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastUsedNextWorkerNodeKey(){let e,t=1/0;for(const[s,r]of this.pool.workerNodes.entries()){const i=r.usage.tasks,o=i.executed+i.executing+i.queued;if(this.isWorkerNodeEligible(s)&&0===o){e=s;break}this.isWorkerNodeEligible(s)&&o<t&&(t=o,e=s)}return e}}class Q extends I{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.nextWorkerNodeKey=this.leastEluNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastEluNextWorkerNodeKey(){let e,t=1/0;for(const[s,r]of this.pool.workerNodes.entries()){const i=r.usage,o=i.elu?.active?.aggregate??0;if(this.isWorkerNodeEligible(s)&&0===o){e=s;break}this.isWorkerNodeEligible(s)&&o<t&&(t=o,e=s)}return e}}class F extends I{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.roundRobinNextWorkerNodeKey(),this.checkNextWorkerNodeEligibility(e),e}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=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 M extends I{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:p,elu:p};defaultWorkerWeight;workerVirtualTaskRunTime=0;constructor(e,t=m){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight()}reset(){return this.resetWorkerNodeKeyProperties(),this.workerVirtualTaskRunTime=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;return this.weightedRoundRobinNextWorkerNodeKey(),this.checkNextWorkerNodeEligibility(e),e}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1),this.workerVirtualTaskRunTime=0),!0}weightedRoundRobinNextWorkerNodeKey(){const e=this.workerVirtualTaskRunTime;return e<(this.opts.weights?.[this.nextWorkerNodeKey??this.previousWorkerNodeKey]??this.defaultWorkerWeight)?this.workerVirtualTaskRunTime=e+this.getWorkerTaskRunTime(this.nextWorkerNodeKey??this.previousWorkerNodeKey):(this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,this.workerVirtualTaskRunTime=0),this.nextWorkerNodeKey}}class K{workerChoiceStrategy;opts;workerChoiceStrategies;choiceRetriesCount=0;constructor(e,t=v.ROUND_ROBIN,s=m){this.workerChoiceStrategy=t,this.opts=s,this.opts={...m,...s},this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[v.ROUND_ROBIN,new(F.bind(this))(e,s)],[v.LEAST_USED,new(O.bind(this))(e,s)],[v.LEAST_BUSY,new(z.bind(this))(e,s)],[v.LEAST_ELU,new(Q.bind(this))(e,s)],[v.FAIR_SHARE,new(C.bind(this))(e,s)],[v.WEIGHTED_ROUND_ROBIN,new(M.bind(this))(e,s)],[v.INTERLEAVED_WEIGHTED_ROUND_ROBIN,new(R.bind(this))(e,s)]])}getStrategyPolicy(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).strategyPolicy}getTaskStatisticsRequirements(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).taskStatisticsRequirements}setWorkerChoiceStrategy(e){this.workerChoiceStrategy!==e&&(this.workerChoiceStrategy=e),this.workerChoiceStrategies.get(this.workerChoiceStrategy)?.reset()}update(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).update(e)}execute(){const e=this.workerChoiceStrategies.get(this.workerChoiceStrategy).choose();if(null==e&&this.choiceRetriesCount<this.opts.choiceRetries)return this.choiceRetriesCount++,this.execute();if(null==e)throw new Error(`Worker node key chosen is null or undefined after ${this.choiceRetriesCount} retries`);return this.choiceRetriesCount=0,e}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 P 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 P(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 q{value;next;prev;constructor(e){this.value=e}}class A{head;tail;size;maxSize;constructor(){this.clear()}push(e){const t=new q(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 q(e);return null==this.head?this.head=this.tail=t:(t.next=this.head,this.head=this.head.prev=t),this.incrementSize()}pop(){if(null==this.head)return;const e=this.tail;return this.tail=this.tail.prev,null==this.tail?this.head=void 0:this.tail.next=void 0,--this.size,e?.value}shift(){if(null==this.head)return;const e=this.head;return this.head=this.head.next,null==this.head?this.tail=void 0:this.head.prev=void 0,--this.size,e?.value}peekFirst(){return this.head?.value}peekLast(){return this.tail?.value}clear(){this.head=void 0,this.tail=void 0,this.size=0,this.maxSize=0}[Symbol.iterator](){let e=this.head;return{next:()=>{if(null==e)return{value:void 0,done:!0};const t={value:e.value,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.value,done:!1};return e=e.prev,t}}}}}incrementSize(){return++this.size,this.size>this.maxSize&&(this.maxSize=this.size),this.size}}const U=Object.freeze({thread:"thread",cluster:"cluster"});class B{worker;info;usage;messageChannel;tasksQueueBackPressureSize;onBackPressure;onEmptyQueue;tasksQueue;onEmptyQueueCount;taskFunctionsUsage;constructor(e,s,r){if(null==e)throw new TypeError("Cannot construct a worker node without a worker");if(null==s)throw new TypeError("Cannot construct a worker node without a worker type");if(null==r)throw new TypeError("Cannot construct a worker node without a tasks queue back pressure size");if(!Number.isSafeInteger(r))throw new TypeError("Cannot construct a worker node with a tasks queue back pressure size that is not an integer");this.worker=e,this.info=this.initWorkerInfo(e,s),this.usage=this.initWorkerUsage(),s===U.thread&&(this.messageChannel=new t.MessageChannel),this.tasksQueueBackPressureSize=r,this.tasksQueue=new A,this.onEmptyQueueCount=0,this.taskFunctionsUsage=new Map}tasksQueueSize(){return this.tasksQueue.size}enqueueTask(e){const t=this.tasksQueue.push(e);return null!=this.onBackPressure&&this.hasBackPressure()&&this.onBackPressure(this.info.id),t}unshiftTask(e){const t=this.tasksQueue.unshift(e);return null!=this.onBackPressure&&this.hasBackPressure()&&this.onBackPressure(this.info.id),t}dequeueTask(){const e=this.tasksQueue.shift();return null!=this.onEmptyQueue&&0===this.tasksQueue.size&&this.startOnEmptyQueue().catch(g),e}popTask(){const e=this.tasksQueue.pop();return null!=this.onEmptyQueue&&0===this.tasksQueue.size&&this.startOnEmptyQueue().catch(g),e}clearTasksQueue(){this.tasksQueue.clear()}hasBackPressure(){return this.tasksQueue.size>=this.tasksQueueBackPressureSize}resetUsage(){this.usage=this.initWorkerUsage(),this.taskFunctionsUsage.clear()}closeChannel(){null!=this.messageChannel&&(this.messageChannel?.port1.unref(),this.messageChannel?.port2.unref(),this.messageChannel?.port1.close(),this.messageChannel?.port2.close(),delete this.messageChannel)}getTaskFunctionWorkerUsage(e){if(!Array.isArray(this.info.taskFunctions))throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function names list is not yet defined`);if(Array.isArray(this.info.taskFunctions)&&this.info.taskFunctions.length<3)throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function names list has less than 3 elements`);return e===l&&(e=this.info.taskFunctions[1]),this.taskFunctionsUsage.has(e)||this.taskFunctionsUsage.set(e,this.initTaskFunctionWorkerUsage(e)),this.taskFunctionsUsage.get(e)}async startOnEmptyQueue(){this.onEmptyQueueCount>0&&(this.usage.tasks.executing>0||this.tasksQueue.size>0)?this.onEmptyQueueCount=0:(this.onEmptyQueue(this.info.id),++this.onEmptyQueueCount,await(async e=>{await new Promise((t=>{setTimeout(t,e)}))})(((e=0,t=100)=>{const s=Math.pow(2,e)*t;return s+.2*s*S()})(this.onEmptyQueueCount)),await this.startOnEmptyQueue())}initWorkerInfo(e,t){return{id:this.getWorkerId(e,t),type:t,dynamic:!1,ready:!1}}initWorkerUsage(){const e=()=>this.tasksQueue.size,t=()=>this.tasksQueue.maxSize;return{tasks:{executed:0,executing:0,get queued(){return e()},get maxQueued(){return t()},stolen:0,failed:0},runTime:{history:new P},waitTime:{history:new P},elu:{idle:{history:new P},active:{history:new P}}}}initTaskFunctionWorkerUsage(e){const t=()=>{let t=0;for(const s of this.tasksQueue)(s.name===l&&e===this.info.taskFunctions[1]||s.name!==l&&e===s.name)&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},stolen:0,failed:0},runTime:{history:new P},waitTime:{history:new P},elu:{idle:{history:new P},active:{history:new P}}}}getWorkerId(e,t){return t===U.thread?e.threadId:t===U.cluster?e.id:void 0}}class D{numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;max;starting;started;startTimestamp;constructor(e,t,s){if(this.numberOfWorkers=e,this.filePath=t,this.opts=s,!this.isMain())throw new Error("Cannot start a pool from a worker with the same type as the pool");this.checkNumberOfWorkers(this.numberOfWorkers),this.checkFilePath(this.filePath),this.checkPoolOptions(this.opts),this.chooseWorkerNode=this.chooseWorkerNode.bind(this),this.executeTask=this.executeTask.bind(this),this.enqueueTask=this.enqueueTask.bind(this),!0===this.opts.enableEvents&&(this.emitter=new c),this.workerChoiceStrategyContext=new K(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook(),this.starting=!0,this.startPool(),this.starting=!1,this.started=!0,this.startTimestamp=i.performance.now()}checkFilePath(e){if(null==e||"string"!=typeof e||"string"==typeof e&&0===e.trim().length)throw new Error("Please specify a file with a worker implementation");if(!o.existsSync(e))throw new Error(`Cannot find the worker file '${e}'`)}checkNumberOfWorkers(e){if(null==e)throw new Error("Cannot instantiate a pool without specifying the number of workers");if(!Number.isSafeInteger(e))throw new TypeError("Cannot instantiate a pool with a non safe integer number of workers");if(e<0)throw new RangeError("Cannot instantiate a pool with a negative number of workers");if(this.type===k.fixed&&0===e)throw new RangeError("Cannot instantiate a fixed pool with zero worker")}checkDynamicPoolSize(e,t){if(this.type===k.dynamic){if(null==t)throw new TypeError("Cannot instantiate a dynamic pool without specifying the maximum pool size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot instantiate a dynamic pool with a non safe integer maximum pool size");if(e>t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size");if(0===t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size equal to zero");if(e===t)throw new RangeError("Cannot instantiate a dynamic pool with a minimum pool size equal to the maximum pool size. Use a fixed pool instead")}}checkPoolOptions(e){if(!T(e))throw new TypeError("Invalid pool options: must be a plain object");this.opts.workerChoiceStrategy=e.workerChoiceStrategy??v.ROUND_ROBIN,this.checkValidWorkerChoiceStrategy(this.opts.workerChoiceStrategy),this.opts.workerChoiceStrategyOptions={...m,...e.workerChoiceStrategyOptions},this.checkValidWorkerChoiceStrategyOptions(this.opts.workerChoiceStrategyOptions),this.opts.restartWorkerOnError=e.restartWorkerOnError??!0,this.opts.enableEvents=e.enableEvents??!0,this.opts.enableTasksQueue=e.enableTasksQueue??!1,this.opts.enableTasksQueue&&(this.checkValidTasksQueueOptions(e.tasksQueueOptions),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e.tasksQueueOptions))}checkValidWorkerChoiceStrategy(e){if(!Object.values(v).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)}checkValidWorkerChoiceStrategyOptions(e){if(!T(e))throw new TypeError("Invalid worker choice strategy options: must be a plain object");if(null!=e.choiceRetries&&!Number.isSafeInteger(e.choiceRetries))throw new TypeError("Invalid worker choice strategy options: choice retries must be an integer");if(null!=e.choiceRetries&&e.choiceRetries<0)throw new RangeError(`Invalid worker choice strategy options: choice retries '${e.choiceRetries}' 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}'`)}checkValidTasksQueueOptions(e){if(null!=e&&!T(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?.queueMaxSize)throw new Error("Invalid tasks queue options: queueMaxSize is deprecated, please use size instead");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`)}startPool(){for(;this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.numberOfWorkers;)this.createAndSetupWorkerNode()}get info(){return{version:"2.6.36",type:this.type,worker:this.worker,ready:this.ready,strategy:this.opts.workerChoiceStrategy,minSize:this.minSize,maxSize:this.maxSize,...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{utilization:f(this.utilization)},workerNodes:this.workerNodes.length,idleWorkerNodes:this.workerNodes.reduce(((e,t)=>0===t.usage.tasks.executing?e+1:e),0),busyWorkerNodes:this.workerNodes.reduce(((e,t)=>t.usage.tasks.executing>0?e+1:e),0),executedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executed),0),executingTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executing),0),...!0===this.opts.enableTasksQueue&&{queuedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.queued),0)},...!0===this.opts.enableTasksQueue&&{maxQueuedTasks:this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.maxQueued??0)),0)},...!0===this.opts.enableTasksQueue&&{backPressure:this.hasBackPressure()},...!0===this.opts.enableTasksQueue&&{stolenTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.stolen),0)},failedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.failed),0),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&{runTime:{minimum:f(Math.min(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:f(Math.max(...this.workerNodes.map((e=>e.usage.runTime?.maximum??-1/0)))),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.average&&{average:f(w(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&{median:f(y(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:f(Math.min(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:f(Math.max(...this.workerNodes.map((e=>e.usage.waitTime?.maximum??-1/0)))),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.average&&{average:f(w(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.waitTime.history)),[])))},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&{median:f(y(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.waitTime.history)),[])))}}}}}get ready(){return this.workerNodes.reduce(((e,t)=>!t.info.dynamic&&t.info.ready?e+1:e),0)>=this.minSize}get utilization(){const e=(i.performance.now()-this.startTimestamp)*this.maxSize;return(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)+this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0))/e}get minSize(){return this.numberOfWorkers}get maxSize(){return this.max??this.numberOfWorkers}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Worker message received without worker id");if(null!=e.workerId&&-1===this.getWorkerNodeKeyByWorkerId(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKeyByWorker(e){return this.workerNodes.findIndex((t=>t.worker===e))}getWorkerNodeKeyByWorkerId(e){return this.workerNodes.findIndex((t=>t.info.id===e))}setWorkerChoiceStrategy(e,t){this.checkValidWorkerChoiceStrategy(e),this.opts.workerChoiceStrategy=e,this.workerChoiceStrategyContext.setWorkerChoiceStrategy(this.opts.workerChoiceStrategy),null!=t&&this.setWorkerChoiceStrategyOptions(t);for(const[e,t]of this.workerNodes.entries())t.resetUsage(),this.sendStatisticsMessageToWorker(e)}setWorkerChoiceStrategyOptions(e){this.checkValidWorkerChoiceStrategyOptions(e),this.opts.workerChoiceStrategyOptions={...m,...e},this.workerChoiceStrategyContext.setOptions(this.opts.workerChoiceStrategyOptions)}enableTasksQueue(e,t){!0!==this.opts.enableTasksQueue||e||this.flushTasksQueues(),this.opts.enableTasksQueue=e,this.setTasksQueueOptions(t)}setTasksQueueOptions(e){!0===this.opts.enableTasksQueue?(this.checkValidTasksQueueOptions(e),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e),this.setTasksQueueMaxSize(this.opts.tasksQueueOptions.size)):null!=this.opts.tasksQueueOptions&&delete this.opts.tasksQueueOptions}setTasksQueueMaxSize(e){for(const t of this.workerNodes)t.tasksQueueBackPressureSize=e}buildTasksQueueOptions(e){return{size:Math.pow(this.maxSize,2),concurrency:1,...e}}get full(){return this.workerNodes.length>=this.maxSize}internalBusy(){return!0===this.opts.enableTasksQueue?-1===this.workerNodes.findIndex((e=>e.info.ready&&e.usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency)):-1===this.workerNodes.findIndex((e=>e.info.ready&&0===e.usage.tasks.executing))}listTaskFunctions(){for(const e of this.workerNodes)if(Array.isArray(e.info.taskFunctions)&&e.info.taskFunctions.length>0)return e.info.taskFunctions;return[]}async execute(e,t,s){return await new Promise(((o,n)=>{if(!this.started)return void n(new Error("Cannot execute a task on destroyed 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 a=i.performance.now(),u=this.chooseWorkerNode(),h=this.getWorkerInfo(u),k={name:t??l,data:e??{},transferList:s,timestamp:a,workerId:h.id,taskId:r.randomUUID()};this.promiseResponseMap.set(k.taskId,{resolve:o,reject:n,workerNodeKey:u}),!1===this.opts.enableTasksQueue||!0===this.opts.enableTasksQueue&&0===this.tasksQueueSize(u)&&this.workerNodes[u].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency?this.executeTask(u,k):this.enqueueTask(u,k)}))}async destroy(){await Promise.all(this.workerNodes.map((async(e,t)=>{await this.destroyWorkerNode(t)}))),this.emitter?.emit(d.destroy,this.info),this.started=!1}async sendKillMessageToWorker(e,t){await new Promise(((s,r)=>{this.registerWorkerMessageListener(e,(e=>{"success"===e.kill?s():"failure"===e.kill&&r(new Error(`Worker ${t} kill message handling failed`))})),this.sendToWorker(e,{kill:!0,workerId:t})}))}setupHook(){}beforeTaskExecutionHook(e,t){if(null!=this.workerNodes[e]?.usage){const s=this.workerNodes[e].usage;++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t)}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name)){const s=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name);++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t)}}afterTaskExecutionHook(e,t){if(null!=this.workerNodes[e]?.usage){const s=this.workerNodes[e].usage;this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t)}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance?.name)){const s=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance?.name);this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t)}}shallUpdateTaskFunctionWorkerUsage(e){const t=this.getWorkerInfo(e);return null!=t&&Array.isArray(t.taskFunctions)&&t.taskFunctions.length>2}updateTaskStatisticsWorkerUsage(e,t){const s=e.tasks;null!=s.executing&&s.executing>0&&--s.executing,null==t.taskError?++s.executed:++s.failed}updateRunTimeWorkerUsage(e,t){null==t.taskError&&x(e.runTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime,t.taskPerformance?.runTime??0)}updateWaitTimeWorkerUsage(e,t){const s=i.performance.now(),r=s-(t.timestamp??s);x(e.waitTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime,r)}updateEluWorkerUsage(e,t){if(null!=t.taskError)return;const s=this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu;x(e.elu.active,s,t.taskPerformance?.elu?.active??0),x(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),r=this.getWorkerInfo(s);r.ready=!1,this.workerNodes[s].closeChannel(),this.emitter?.emit(d.error,t),!0===this.opts.restartWorkerOnError&&!this.starting&&this.started&&(r.dynamic?this.createAndSetupDynamicWorkerNode():this.createAndSetupWorkerNode()),!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=>{const t=this.getWorkerNodeKeyByWorkerId(e.workerId),s=this.workerNodes[t].usage;(W(E.HARD,e.kill)||W(E.SOFT,e.kill)&&(!1===this.opts.enableTasksQueue&&0===s.tasks.executing||!0===this.opts.enableTasksQueue&&0===s.tasks.executing&&0===this.tasksQueueSize(t)))&&this.destroyWorkerNode(t).catch((e=>{this.emitter?.emit(d.error,e)}))}));const t=this.getWorkerInfo(e);return this.sendToWorker(e,{checkActive:!0,workerId:t.id}),t.dynamic=!0,(this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerReady||this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerUsage)&&(t.ready=!0),this.checkAndEmitDynamicWorkerCreationEvents(),e}afterWorkerNodeSetup(e){this.registerWorkerMessageListener(e,this.workerListener()),this.sendStartupMessageToWorker(e),this.sendStatisticsMessageToWorker(e),!0===this.opts.enableTasksQueue&&(this.workerNodes[e].onEmptyQueue=this.taskStealingOnEmptyQueue.bind(this),this.workerNodes[e].onBackPressure=this.tasksStealingOnBackPressure.bind(this))}sendStatisticsMessageToWorker(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate},workerId:this.getWorkerInfo(e).id})}redistributeQueuedTasks(e){for(;this.tasksQueueSize(e)>0;){let t,s=1/0;for(const[r,i]of this.workerNodes.entries())if(i.info.ready&&r!==e){if(0===i.usage.tasks.queued){t=r;break}i.usage.tasks.queued<s&&(s=i.usage.tasks.queued,t=r)}if(null!=t){const s=this.workerNodes[t],r={...this.dequeueTask(e),workerId:s.info.id};0===this.tasksQueueSize(t)&&s.usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency?this.executeTask(t,r):this.enqueueTask(t,r)}}}taskStealingOnEmptyQueue(e){const t=this.getWorkerNodeKeyByWorkerId(e),s=this.workerNodes[t],r=this.workerNodes.slice().sort(((e,t)=>t.usage.tasks.queued-e.usage.tasks.queued));for(const i of r){if(0===i.usage.tasks.queued)break;if(i.info.ready&&i.info.id!==e&&i.usage.tasks.queued>0){const e={...i.popTask(),workerId:s.info.id};if(0===this.tasksQueueSize(t)&&s.usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency?this.executeTask(t,e):this.enqueueTask(t,e),null!=s?.usage&&++s.usage.tasks.stolen,this.shallUpdateTaskFunctionWorkerUsage(t)&&null!=s.getTaskFunctionWorkerUsage(e.name)){++s.getTaskFunctionWorkerUsage(e.name).tasks.stolen}break}}}tasksStealingOnBackPressure(e){if(this.opts.tasksQueueOptions?.size<=1)return;const t=this.workerNodes[this.getWorkerNodeKeyByWorkerId(e)],s=this.workerNodes.slice().sort(((e,t)=>e.usage.tasks.queued-t.usage.tasks.queued));for(const[r,i]of s.entries())if(t.usage.tasks.queued>0&&i.info.ready&&i.info.id!==e&&i.usage.tasks.queued<this.opts.tasksQueueOptions?.size-1){const e={...t.popTask(),workerId:i.info.id};if(0===this.tasksQueueSize(r)&&i.usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency?this.executeTask(r,e):this.enqueueTask(r,e),null!=i?.usage&&++i.usage.tasks.stolen,this.shallUpdateTaskFunctionWorkerUsage(r)&&null!=i.getTaskFunctionWorkerUsage(e.name)){++i.getTaskFunctionWorkerUsage(e.name).tasks.stolen}}}workerListener(){return e=>{this.checkMessageWorkerId(e),null!=e.ready&&null!=e.taskFunctions?this.handleWorkerReadyResponse(e):null!=e.taskId?this.handleTaskExecutionResponse(e):null!=e.taskFunctions&&(this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId)).taskFunctions=e.taskFunctions)}}handleWorkerReadyResponse(e){if(!1===e.ready)throw new Error(`Worker ${e.workerId} failed to initialize`);const t=this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId));t.ready=e.ready,t.taskFunctions=e.taskFunctions,null!=this.emitter&&this.ready&&this.emitter.emit(d.ready,this.info)}handleTaskExecutionResponse(e){const{taskId:t,taskError:s,data:r}=e,i=this.promiseResponseMap.get(t);if(null!=i){null!=s?(this.emitter?.emit(d.taskError,s),i.reject(s.message)):i.resolve(r);const o=i.workerNodeKey;this.afterTaskExecutionHook(o,e),this.promiseResponseMap.delete(t),!0===this.opts.enableTasksQueue&&this.tasksQueueSize(o)>0&&this.workerNodes[o].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&this.executeTask(o,this.dequeueTask(o)),this.workerChoiceStrategyContext.update(o)}}checkAndEmitTaskExecutionEvents(){this.busy&&this.emitter?.emit(d.busy,this.info)}checkAndEmitTaskQueuingEvents(){this.hasBackPressure()&&this.emitter?.emit(d.backPressure,this.info)}checkAndEmitDynamicWorkerCreationEvents(){this.type===k.dynamic&&this.full&&this.emitter?.emit(d.full,this.info)}getWorkerInfo(e){return this.workerNodes[e]?.info}addWorkerNode(e){const t=new B(e,this.worker,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 node added not found");return s}removeWorkerNode(e){const t=this.getWorkerNodeKeyByWorker(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategyContext.remove(t))}hasWorkerNodeBackPressure(e){return!0===this.opts.enableTasksQueue&&this.workerNodes[e].hasBackPressure()}hasBackPressure(){return!0===this.opts.enableTasksQueue&&-1===this.workerNodes.findIndex((e=>!e.hasBackPressure()))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(e,t,t.transferList),this.checkAndEmitTaskExecutionEvents()}enqueueTask(e,t){const s=this.workerNodes[e].enqueueTask(t);return this.checkAndEmitTaskQueuingEvents(),s}dequeueTask(e){return this.workerNodes[e].dequeueTask()}tasksQueueSize(e){return this.workerNodes[e].tasksQueueSize()}flushTasksQueue(e){for(;this.tasksQueueSize(e)>0;)this.executeTask(e,this.dequeueTask(e));this.workerNodes[e].clearTasksQueue()}flushTasksQueues(){for(const[e]of this.workerNodes.entries())this.flushTasksQueue(e)}}class L extends D{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}setupHook(){s.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return s.isPrimary}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e].worker,s=new Promise((e=>{t.on("exit",(()=>{e()}))}));t.on("disconnect",(()=>{t.kill()})),await this.sendKillMessageToWorker(e,t.id),t.disconnect(),await s}sendToWorker(e,t){this.workerNodes[e].worker.send(t)}sendStartupMessageToWorker(e){this.sendToWorker(e,{ready:!1,workerId:this.workerNodes[e].worker.id})}registerWorkerMessageListener(e,t){this.workerNodes[e].worker.on("message",t)}createWorker(){return s.fork(this.opts.env)}get type(){return k.fixed}get worker(){return U.cluster}get busy(){return this.internalBusy()}}class _ extends D{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}isMain(){return t.isMainThread}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e],s=t.worker,r=new Promise((e=>{s.on("exit",(()=>{e()}))}));await this.sendKillMessageToWorker(e,s.threadId),t.closeChannel(),await s.terminate(),await r}sendToWorker(e,t,s){this.workerNodes[e].messageChannel.port1.postMessage(t,s)}sendStartupMessageToWorker(e){const t=this.workerNodes[e].worker,s=this.workerNodes[e].messageChannel.port2;t.postMessage({ready:!1,workerId:t.threadId,port:s},[s])}registerWorkerMessageListener(e,t){this.workerNodes[e].messageChannel.port1.on("message",t)}createWorker(){return new t.Worker(this.filePath,{env:t.SHARE_ENV,...this.opts.workerOptions})}get type(){return k.fixed}get worker(){return U.thread}get busy(){return this.internalBusy()}}const V=6e4,j={killBehavior:E.SOFT,maxInactiveTime:V,killHandler:g};class H extends a.AsyncResource{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,s,r,i=j){if(super(e),this.isMain=t,this.mainWorker=s,this.opts=i,null==this.isMain)throw new Error("isMain parameter is mandatory");this.checkTaskFunctions(r),this.checkWorkerOptions(this.opts),this.isMain||this.getMainWorker().on("message",this.handleReadyMessage.bind(this))}checkWorkerOptions(e){this.opts={...j,...e},delete this.opts.async}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(!T(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)){if("string"!=typeof s)throw new TypeError("A taskFunctions parameter object key is not a string");if("string"==typeof s&&0===s.trim().length)throw new TypeError("A taskFunctions parameter object key is an empty string");if("function"!=typeof r)throw new TypeError("A taskFunctions parameter object value is not a function");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){return this.checkTaskFunctionName(e),this.taskFunctions.has(e)}addTaskFunction(e,t){if(this.checkTaskFunctionName(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");try{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.sendTaskFunctionsListToMainWorker(),!0}catch{return!1}}removeTaskFunction(e){if(this.checkTaskFunctionName(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.sendTaskFunctionsListToMainWorker(),t}listTaskFunctions(){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){if(this.checkTaskFunctionName(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");try{return this.taskFunctions.set(l,this.taskFunctions.get(e)),!0}catch{return!1}}checkTaskFunctionName(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("name parameter is an empty string")}messageListener(e){this.checkMessageWorkerId(e),null!=e.statistics?this.statistics=e.statistics:null!=e.checkActive?e.checkActive?this.startCheckActive():this.stopCheckActive():null!=e.taskId&&null!=e.data?this.run(e):!0===e.kill&&this.handleKillMessage(e)}handleKillMessage(e){if(this.stopCheckActive(),N(this.opts.killHandler))(this.opts.killHandler?.()).then((()=>(this.sendToMainWorker({kill:"success",workerId:this.id}),null))).catch((()=>{this.sendToMainWorker({kill:"failure",workerId:this.id})})).finally((()=>{this.emitDestroy()})).catch(g);else try{this.opts.killHandler?.(),this.sendToMainWorker({kill:"success",workerId:this.id})}catch{this.sendToMainWorker({kill:"failure",workerId:this.id})}finally{this.emitDestroy()}}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Message worker id is not set");if(null!=e.workerId&&e.workerId!==this.id)throw new Error(`Message worker id ${e.workerId} does not match the worker id ${this.id}`)}startCheckActive(){this.lastTaskTimestamp=i.performance.now(),this.activeInterval=setInterval(this.checkActive.bind(this),(this.opts.maxInactiveTime??V)/2)}stopCheckActive(){null!=this.activeInterval&&(clearInterval(this.activeInterval),delete this.activeInterval)}checkActive(){i.performance.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??V)&&this.sendToMainWorker({kill:this.opts.killBehavior,workerId:this.id})}getMainWorker(){if(null==this.mainWorker)throw new Error("Main worker not set");return this.mainWorker}sendTaskFunctionsListToMainWorker(){this.sendToMainWorker({taskFunctions:this.listTaskFunctions(),workerId:this.id})}handleError(e){return e instanceof Error?e.message:e}run(e){const{name:t,taskId:s,data:r}=e,i=this.taskFunctions.get(t??l);null!=i?N(i)?this.runInAsyncScope(this.runAsync.bind(this),this,i,e):this.runInAsyncScope(this.runSync.bind(this),this,i,e):this.sendToMainWorker({taskError:{name:t,message:`Task function '${t}' not found`,data:r},workerId:this.id,taskId:s})}runSync(e,t){const{name:s,taskId:r,data:i}=t;try{let t=this.beginTaskPerformance(s);const o=e(i);t=this.endTaskPerformance(t),this.sendToMainWorker({data:o,taskPerformance:t,workerId:this.id,taskId:r})}catch(e){const t=this.handleError(e);this.sendToMainWorker({taskError:{name:s,message:t,data:i},workerId:this.id,taskId:r})}finally{this.updateLastTaskTimestamp()}}runAsync(e,t){const{name:s,taskId:r,data:i}=t;let o=this.beginTaskPerformance(s);e(i).then((e=>(o=this.endTaskPerformance(o),this.sendToMainWorker({data:e,taskPerformance:o,workerId:this.id,taskId:r}),null))).catch((e=>{const t=this.handleError(e);this.sendToMainWorker({taskError:{name:s,message:t,data:i},workerId:this.id,taskId:r})})).finally((()=>{this.updateLastTaskTimestamp()})).catch(g)}beginTaskPerformance(e){return this.checkStatistics(),{name:e??l,timestamp:i.performance.now(),...this.statistics.elu&&{elu:i.performance.eventLoopUtilization()}}}endTaskPerformance(e){return this.checkStatistics(),{...e,...this.statistics.runTime&&{runTime:i.performance.now()-e.timestamp},...this.statistics.elu&&{elu:i.performance.eventLoopUtilization(e.elu)}}}checkStatistics(){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set")}updateLastTaskTimestamp(){null!=this.activeInterval&&(this.lastTaskTimestamp=i.performance.now())}}exports.ClusterWorker=class extends H{constructor(e,t={}){super("worker-cluster-pool:poolifier",s.isPrimary,s.worker,e,t)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready)try{this.getMainWorker().on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctions:this.listTaskFunctions(),workerId:this.id})}catch{this.sendToMainWorker({ready:!1,taskFunctions:this.listTaskFunctions(),workerId:this.id})}}get id(){return this.getMainWorker().id}sendToMainWorker(e){this.getMainWorker().send(e)}},exports.DynamicClusterPool=class extends L{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return k.dynamic}get busy(){return this.full&&this.internalBusy()}},exports.DynamicThreadPool=class extends _{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return k.dynamic}get busy(){return this.full&&this.internalBusy()}},exports.FixedClusterPool=L,exports.FixedThreadPool=_,exports.KillBehaviors=E,exports.Measurements=b,exports.PoolEvents=d,exports.PoolTypes=k,exports.ThreadWorker=class extends H{port;constructor(e,s={}){super("worker-thread-pool:poolifier",t.isMainThread,t.parentPort,e,s)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready&&null!=e.port)try{this.port=e.port,this.port.on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctions:this.listTaskFunctions(),workerId:this.id})}catch{this.sendToMainWorker({ready:!1,taskFunctions:this.listTaskFunctions(),workerId:this.id})}}handleKillMessage(e){super.handleKillMessage(e),this.port?.unref(),this.port?.close()}get id(){return t.threadId}sendToMainWorker(e){this.port.postMessage(e)}handleError(e){return e}},exports.WorkerChoiceStrategies=v,exports.WorkerTypes=U,exports.availableParallelism=()=>{let e=1;try{e=h.availableParallelism()}catch{const t=h.cpus();Array.isArray(t)&&t.length>0&&(e=t.length)}return e};
1
+ "use strict";var e=require("node:events"),t=require("node:worker_threads"),s=require("node:cluster"),r=require("node:crypto"),i=require("node:perf_hooks"),o=require("node:fs"),n=require("node:os"),a=require("node:async_hooks");function h(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 u=h(n);const k=Object.freeze({fixed:"fixed",dynamic:"dynamic"});class c extends e.EventEmitter{}const d=Object.freeze({ready:"ready",busy:"busy",full:"full",destroy:"destroy",error:"error",taskError:"taskError",backPressure:"backPressure"}),l=Object.freeze({thread:"thread",cluster:"cluster"}),g="default",m=Object.freeze((()=>{})),p={retries:6,runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},w={aggregate:!1,average:!1,median:!1},y=e=>e instanceof t.Worker?l.thread:e instanceof s.Worker?l.cluster:void 0,f=e=>e instanceof t.Worker?e.threadId:e instanceof s.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,W=e=>{if(Array.isArray(e)&&0===e.length)return 0;if(Array.isArray(e)&&1===e.length)return e[0];const t=e.slice().sort(((e,t)=>e-t));return(t[t.length-1>>1]+t[t.length>>1])/2},N=(e,t=2)=>{const s=Math.pow(10,t);return Math.round(e*s*(1+Number.EPSILON))/s},x=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),S=(e,t)=>t===e,E=e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name,v=(e,t,s)=>{t.aggregate&&(e.aggregate=(e.aggregate??0)+s,e.minimum=Math.min(s,e.minimum??1/0),e.maximum=Math.max(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=W(e.history):null!=e.median&&delete e.median))},b=()=>r.webcrypto.getRandomValues(new Uint32Array(1))[0]/4294967296,C=Object.freeze({SOFT:"SOFT",HARD:"HARD"}),I=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"}),R=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"});class z{pool;opts;nextWorkerNodeKey=0;previousWorkerNodeKey=0;strategyPolicy={dynamicWorkerUsage:!1,dynamicWorkerReady:!0};taskStatisticsRequirements={runTime:w,waitTime:w,elu:w};constructor(e,t=p){this.pool=e,this.opts=t,this.opts={...p,...t},this.choose=this.choose.bind(this)}setTaskStatisticsRequirements(e){this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.runTime,e.runTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.waitTime,e.waitTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.elu,e.elu?.median)}toggleMedianMeasurementStatisticsRequirements(e,t){e.average&&t&&(e.average=!1,e.median=t),e.median&&!t&&(e.average=!0,e.median=t)}resetWorkerNodeKeyProperties(){this.nextWorkerNodeKey=0,this.previousWorkerNodeKey=0}setOptions(e){this.opts={...p,...e},this.setTaskStatisticsRequirements(this.opts)}isWorkerNodeReady(e){return this.pool.workerNodes[e].info.ready}hasWorkerNodeBackPressure(e){return this.pool.hasWorkerNodeBackPressure(e)}isWorkerNodeEligible(e){return this.isWorkerNodeReady(e)&&!this.hasWorkerNodeBackPressure(e)}getWorkerTaskRunTime(e){return this.taskStatisticsRequirements.runTime.median?this.pool.workerNodes[e].usage.runTime?.median??0:this.pool.workerNodes[e].usage.runTime?.average??0}getWorkerTaskWaitTime(e){return this.taskStatisticsRequirements.waitTime.median?this.pool.workerNodes[e].usage.waitTime?.median??0:this.pool.workerNodes[e].usage.waitTime?.average??0}getWorkerTaskElu(e){return this.taskStatisticsRequirements.elu.median?this.pool.workerNodes[e].usage.elu.active?.median??0:this.pool.workerNodes[e].usage.elu.active?.average??0}checkNextWorkerNodeEligibility(e){this.isWorkerNodeEligible(this.nextWorkerNodeKey)||(this.nextWorkerNodeKey=void 0,this.previousWorkerNodeKey=e??this.previousWorkerNodeKey)}computeDefaultWorkerWeight(){let e=0;for(const t of n.cpus()){const s=t.speed.toString().length-1;e+=1/(t.speed/Math.pow(10,s))*Math.pow(10,s)}return Math.round(e/n.cpus().length)}}class O extends z{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:w,elu:{aggregate:!0,average:!0,median:!1}};workersVirtualTaskEndTimestamp=[];constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.workersVirtualTaskEndTimestamp=[],!0}update(e){return this.computeWorkerVirtualTaskEndTimestamp(e),!0}choose(){return this.nextWorkerNodeKey=this.fairShareNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(e){return this.workersVirtualTaskEndTimestamp.splice(e,1),!0}fairShareNextWorkerNodeKey(){let e,t=1/0;for(const[s]of this.pool.workerNodes.entries()){if(!this.isWorkerNodeEligible(s))continue;null==this.workersVirtualTaskEndTimestamp[s]&&this.computeWorkerVirtualTaskEndTimestamp(s);const r=this.workersVirtualTaskEndTimestamp[s];r<t&&(t=r,e=s)}return e}computeWorkerVirtualTaskEndTimestamp(e){this.workersVirtualTaskEndTimestamp[e]=this.getWorkerVirtualTaskEndTimestamp(e,this.getWorkerVirtualTaskStartTimestamp(e))}getWorkerVirtualTaskEndTimestamp(e,t){return t+(this.opts.measurement===R.elu?this.getWorkerTaskElu(e):this.getWorkerTaskRunTime(e))}getWorkerVirtualTaskStartTimestamp(e){return Math.max(performance.now(),this.workersVirtualTaskEndTimestamp[e]??-1/0)}}class F extends z{roundId=0;roundWeights;defaultWorkerWeight;constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight(),this.roundWeights=this.getRoundWeights()}reset(){return this.resetWorkerNodeKeyProperties(),this.roundId=0,!0}update(){return!0}choose(){let e,t;for(let s=this.roundId;s<this.roundWeights.length;s++){e=s;for(let e=this.nextWorkerNodeKey??this.previousWorkerNodeKey;e<this.pool.workerNodes.length;e++){if(!this.isWorkerNodeEligible(e))continue;if((this.opts.weights?.[e]??this.defaultWorkerWeight)>=this.roundWeights[s]){t=e;break}}}this.roundId=e,null==t&&(this.previousWorkerNodeKey=this.nextWorkerNodeKey??this.previousWorkerNodeKey),this.nextWorkerNodeKey=t;const s=this.nextWorkerNodeKey;return this.nextWorkerNodeKey===this.pool.workerNodes.length-1?(this.nextWorkerNodeKey=0,this.roundId=this.roundId===this.roundWeights.length-1?0:this.roundId+1):this.nextWorkerNodeKey=(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,s}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1,this.roundId=this.roundId===this.roundWeights.length-1?0:this.roundId+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 M extends z{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:w};constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.nextWorkerNodeKey=this.leastBusyNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastBusyNextWorkerNodeKey(){let e,t=1/0;for(const[s,r]of this.pool.workerNodes.entries()){if(!this.isWorkerNodeEligible(s))continue;const i=(r.usage.runTime?.aggregate??0)+(r.usage.waitTime?.aggregate??0);if(0===i){e=s;break}i<t&&(t=i,e=s)}return e}}class Q extends z{constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.nextWorkerNodeKey=this.leastUsedNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastUsedNextWorkerNodeKey(){let e,t=1/0;for(const[s,r]of this.pool.workerNodes.entries()){if(!this.isWorkerNodeEligible(s))continue;const i=r.usage.tasks,o=i.executed+i.executing+i.queued;if(0===o){e=s;break}o<t&&(t=o,e=s)}return e}}class K extends z{taskStatisticsRequirements={runTime:w,waitTime:w,elu:{aggregate:!0,average:!1,median:!1}};constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.nextWorkerNodeKey=this.leastEluNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastEluNextWorkerNodeKey(){let e,t=1/0;for(const[s,r]of this.pool.workerNodes.entries()){if(!this.isWorkerNodeEligible(s))continue;const i=r.usage,o=i.elu?.active?.aggregate??0;if(0===o){e=s;break}o<t&&(t=o,e=s)}return e}}class P extends z{constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.resetWorkerNodeKeyProperties(),!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;return this.roundRobinNextWorkerNodeKey(),this.checkNextWorkerNodeEligibility(e),e}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=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 q extends z{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:w,elu:w};defaultWorkerWeight;workerVirtualTaskRunTime=0;constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight()}reset(){return this.resetWorkerNodeKeyProperties(),this.workerVirtualTaskRunTime=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;return this.weightedRoundRobinNextWorkerNodeKey(),this.checkNextWorkerNodeEligibility(e),e}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1),this.workerVirtualTaskRunTime=0),!0}weightedRoundRobinNextWorkerNodeKey(){const e=this.workerVirtualTaskRunTime;return e<(this.opts.weights?.[this.nextWorkerNodeKey??this.previousWorkerNodeKey]??this.defaultWorkerWeight)?this.workerVirtualTaskRunTime=e+this.getWorkerTaskRunTime(this.nextWorkerNodeKey??this.previousWorkerNodeKey):(this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,this.workerVirtualTaskRunTime=0),this.nextWorkerNodeKey}}class A{workerChoiceStrategy;opts;workerChoiceStrategies;retriesCount=0;constructor(e,t=I.ROUND_ROBIN,s=p){this.workerChoiceStrategy=t,this.opts=s,this.opts={...p,...s},this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[I.ROUND_ROBIN,new(P.bind(this))(e,s)],[I.LEAST_USED,new(Q.bind(this))(e,s)],[I.LEAST_BUSY,new(M.bind(this))(e,s)],[I.LEAST_ELU,new(K.bind(this))(e,s)],[I.FAIR_SHARE,new(O.bind(this))(e,s)],[I.WEIGHTED_ROUND_ROBIN,new(q.bind(this))(e,s)],[I.INTERLEAVED_WEIGHTED_ROUND_ROBIN,new(F.bind(this))(e,s)]])}getStrategyPolicy(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).strategyPolicy}getTaskStatisticsRequirements(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).taskStatisticsRequirements}setWorkerChoiceStrategy(e){this.workerChoiceStrategy!==e&&(this.workerChoiceStrategy=e),this.workerChoiceStrategies.get(this.workerChoiceStrategy)?.reset()}update(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).update(e)}execute(){const e=this.workerChoiceStrategies.get(this.workerChoiceStrategy).choose();if(null==e&&this.retriesCount<this.opts.retries)return this.retriesCount++,this.execute();if(null==e)throw new Error(`Worker node key chosen is null or undefined after ${this.retriesCount} retries`);return this.retriesCount=0,e}remove(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).remove(e)}setOptions(e){this.opts={...p,...e};for(const t of this.workerChoiceStrategies.values())t.setOptions(e)}}class U 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 U(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 B{data;next;prev;constructor(e){this.data=e}}class D{head;tail;size;maxSize;constructor(){this.clear()}push(e){const t=new B(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 B(e);return null==this.head?this.head=this.tail=t:(t.next=this.head,this.head=this.head.prev=t),this.incrementSize()}pop(){if(null==this.head)return;const e=this.tail;return this.tail=this.tail.prev,null==this.tail?this.head=void 0:this.tail.next=void 0,--this.size,e?.data}shift(){if(null==this.head)return;const e=this.head;return this.head=this.head.next,null==this.head?this.tail=void 0:this.head.prev=void 0,--this.size,e?.data}peekFirst(){return this.head?.data}peekLast(){return this.tail?.data}clear(){this.head=void 0,this.tail=void 0,this.size=0,this.maxSize=0}[Symbol.iterator](){let e=this.head;return{next:()=>{if(null==e)return{value:void 0,done:!0};const t={value:e.data,done:!1};return e=e.next,t}}}backward(){return{[Symbol.iterator]:()=>{let e=this.tail;return{next:()=>{if(null==e)return{value:void 0,done:!0};const t={value:e.data,done:!1};return e=e.prev,t}}}}}incrementSize(){return++this.size,this.size>this.maxSize&&(this.maxSize=this.size),this.size}}class L{worker;info;usage;messageChannel;tasksQueueBackPressureSize;onBackPressure;onEmptyQueue;tasksQueue;onEmptyQueueCount;taskFunctionsUsage;constructor(e,s){if(null==e)throw new TypeError("Cannot construct a worker node without a worker");if(null==s)throw new TypeError("Cannot construct a worker node without a tasks queue back pressure size");if(!Number.isSafeInteger(s))throw new TypeError("Cannot construct a worker node with a tasks queue back pressure size that is not an integer");this.worker=e,this.info=this.initWorkerInfo(e),this.usage=this.initWorkerUsage(),this.info.type===l.thread&&(this.messageChannel=new t.MessageChannel),this.tasksQueueBackPressureSize=s,this.tasksQueue=new D,this.onEmptyQueueCount=0,this.taskFunctionsUsage=new Map}tasksQueueSize(){return this.tasksQueue.size}enqueueTask(e){const t=this.tasksQueue.push(e);return null!=this.onBackPressure&&this.hasBackPressure()&&this.onBackPressure(this.info.id),t}unshiftTask(e){const t=this.tasksQueue.unshift(e);return null!=this.onBackPressure&&this.hasBackPressure()&&this.onBackPressure(this.info.id),t}dequeueTask(){const e=this.tasksQueue.shift();return null!=this.onEmptyQueue&&0===this.tasksQueue.size&&this.startOnEmptyQueue().catch(m),e}popTask(){const e=this.tasksQueue.pop();return null!=this.onEmptyQueue&&0===this.tasksQueue.size&&this.startOnEmptyQueue().catch(m),e}clearTasksQueue(){this.tasksQueue.clear()}hasBackPressure(){return this.tasksQueue.size>=this.tasksQueueBackPressureSize}resetUsage(){this.usage=this.initWorkerUsage(),this.taskFunctionsUsage.clear()}closeChannel(){null!=this.messageChannel&&(this.messageChannel?.port1.unref(),this.messageChannel?.port2.unref(),this.messageChannel?.port1.close(),this.messageChannel?.port2.close(),delete this.messageChannel)}getTaskFunctionWorkerUsage(e){if(!Array.isArray(this.info.taskFunctions))throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function names list is not yet defined`);if(Array.isArray(this.info.taskFunctions)&&this.info.taskFunctions.length<3)throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function names list has less than 3 elements`);return e===g&&(e=this.info.taskFunctions[1]),this.taskFunctionsUsage.has(e)||this.taskFunctionsUsage.set(e,this.initTaskFunctionWorkerUsage(e)),this.taskFunctionsUsage.get(e)}async startOnEmptyQueue(){this.onEmptyQueueCount>0&&(this.usage.tasks.executing>0||this.tasksQueue.size>0)?this.onEmptyQueueCount=0:(this.onEmptyQueue(this.info.id),++this.onEmptyQueueCount,await(async e=>{await new Promise((t=>{setTimeout(t,e)}))})(((e=0,t=100)=>{const s=Math.pow(2,e)*t;return s+.2*s*b()})(this.onEmptyQueueCount)),await this.startOnEmptyQueue())}initWorkerInfo(e){return{id:f(e),type:y(e),dynamic:!1,ready:!1}}initWorkerUsage(){const e=()=>this.tasksQueue.size,t=()=>this.tasksQueue.maxSize;return{tasks:{executed:0,executing:0,get queued(){return e()},get maxQueued(){return t()},stolen:0,failed:0},runTime:{history:new U},waitTime:{history:new U},elu:{idle:{history:new U},active:{history:new U}}}}initTaskFunctionWorkerUsage(e){const t=()=>{let t=0;for(const s of this.tasksQueue)(s.name===g&&e===this.info.taskFunctions[1]||s.name!==g&&e===s.name)&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},stolen:0,failed:0},runTime:{history:new U},waitTime:{history:new U},elu:{idle:{history:new U},active:{history:new U}}}}}class V{numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;max;starting;started;startTimestamp;constructor(e,t,s){if(this.numberOfWorkers=e,this.filePath=t,this.opts=s,!this.isMain())throw new Error("Cannot start a pool from a worker with the same type as the pool");this.checkNumberOfWorkers(this.numberOfWorkers),this.checkFilePath(this.filePath),this.checkPoolOptions(this.opts),this.chooseWorkerNode=this.chooseWorkerNode.bind(this),this.executeTask=this.executeTask.bind(this),this.enqueueTask=this.enqueueTask.bind(this),!0===this.opts.enableEvents&&(this.emitter=new c),this.workerChoiceStrategyContext=new A(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook(),this.starting=!0,this.startPool(),this.starting=!1,this.started=!0,this.startTimestamp=i.performance.now()}checkFilePath(e){if(null==e||"string"!=typeof e||"string"==typeof e&&0===e.trim().length)throw new Error("Please specify a file with a worker implementation");if(!o.existsSync(e))throw new Error(`Cannot find the worker file '${e}'`)}checkNumberOfWorkers(e){if(null==e)throw new Error("Cannot instantiate a pool without specifying the number of workers");if(!Number.isSafeInteger(e))throw new TypeError("Cannot instantiate a pool with a non safe integer number of workers");if(e<0)throw new RangeError("Cannot instantiate a pool with a negative number of workers");if(this.type===k.fixed&&0===e)throw new RangeError("Cannot instantiate a fixed pool with zero worker")}checkDynamicPoolSize(e,t){if(this.type===k.dynamic){if(null==t)throw new TypeError("Cannot instantiate a dynamic pool without specifying the maximum pool size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot instantiate a dynamic pool with a non safe integer maximum pool size");if(e>t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size");if(0===t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size equal to zero");if(e===t)throw new RangeError("Cannot instantiate a dynamic pool with a minimum pool size equal to the maximum pool size. Use a fixed pool instead")}}checkPoolOptions(e){if(!x(e))throw new TypeError("Invalid pool options: must be a plain object");this.opts.workerChoiceStrategy=e.workerChoiceStrategy??I.ROUND_ROBIN,this.checkValidWorkerChoiceStrategy(this.opts.workerChoiceStrategy),this.opts.workerChoiceStrategyOptions={...p,...e.workerChoiceStrategyOptions},this.checkValidWorkerChoiceStrategyOptions(this.opts.workerChoiceStrategyOptions),this.opts.restartWorkerOnError=e.restartWorkerOnError??!0,this.opts.enableEvents=e.enableEvents??!0,this.opts.enableTasksQueue=e.enableTasksQueue??!1,this.opts.enableTasksQueue&&(this.checkValidTasksQueueOptions(e.tasksQueueOptions),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e.tasksQueueOptions))}checkValidWorkerChoiceStrategy(e){if(!Object.values(I).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)}checkValidWorkerChoiceStrategyOptions(e){if(!x(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(R).includes(e.measurement))throw new Error(`Invalid worker choice strategy options: invalid measurement '${e.measurement}'`)}checkValidTasksQueueOptions(e){if(null!=e&&!x(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?.queueMaxSize)throw new Error("Invalid tasks queue options: queueMaxSize is deprecated, please use size instead");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`)}startPool(){for(;this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.numberOfWorkers;)this.createAndSetupWorkerNode()}get info(){return{version:"2.6.37",type:this.type,worker:this.worker,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(Math.min(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:N(Math.max(...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(W(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:N(Math.min(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:N(Math.max(...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(W(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.waitTime.history)),[])))}}}}}get ready(){return this.workerNodes.reduce(((e,t)=>!t.info.dynamic&&t.info.ready?e+1:e),0)>=this.minSize}get utilization(){const e=(i.performance.now()-this.startTimestamp)*this.maxSize;return(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)+this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0))/e}get minSize(){return this.numberOfWorkers}get maxSize(){return this.max??this.numberOfWorkers}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Worker message received without worker id");if(null!=e.workerId&&-1===this.getWorkerNodeKeyByWorkerId(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKeyByWorker(e){return this.workerNodes.findIndex((t=>t.worker===e))}getWorkerNodeKeyByWorkerId(e){return this.workerNodes.findIndex((t=>t.info.id===e))}setWorkerChoiceStrategy(e,t){this.checkValidWorkerChoiceStrategy(e),this.opts.workerChoiceStrategy=e,this.workerChoiceStrategyContext.setWorkerChoiceStrategy(this.opts.workerChoiceStrategy),null!=t&&this.setWorkerChoiceStrategyOptions(t);for(const[e,t]of this.workerNodes.entries())t.resetUsage(),this.sendStatisticsMessageToWorker(e)}setWorkerChoiceStrategyOptions(e){this.checkValidWorkerChoiceStrategyOptions(e),this.opts.workerChoiceStrategyOptions={...p,...e},this.workerChoiceStrategyContext.setOptions(this.opts.workerChoiceStrategyOptions)}enableTasksQueue(e,t){!0!==this.opts.enableTasksQueue||e||this.flushTasksQueues(),this.opts.enableTasksQueue=e,this.setTasksQueueOptions(t)}setTasksQueueOptions(e){!0===this.opts.enableTasksQueue?(this.checkValidTasksQueueOptions(e),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e),this.setTasksQueueMaxSize(this.opts.tasksQueueOptions.size)):null!=this.opts.tasksQueueOptions&&delete this.opts.tasksQueueOptions}setTasksQueueMaxSize(e){for(const t of this.workerNodes)t.tasksQueueBackPressureSize=e}buildTasksQueueOptions(e){return{size:Math.pow(this.maxSize,2),concurrency:1,...e}}get full(){return this.workerNodes.length>=this.maxSize}internalBusy(){return!0===this.opts.enableTasksQueue?-1===this.workerNodes.findIndex((e=>e.info.ready&&e.usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency)):-1===this.workerNodes.findIndex((e=>e.info.ready&&0===e.usage.tasks.executing))}listTaskFunctions(){for(const e of this.workerNodes)if(Array.isArray(e.info.taskFunctions)&&e.info.taskFunctions.length>0)return e.info.taskFunctions;return[]}shallExecuteTask(e){return 0===this.tasksQueueSize(e)&&this.workerNodes[e].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency}async execute(e,t,s){return await new Promise(((o,n)=>{if(!this.started)return void n(new Error("Cannot execute a task on destroyed 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 a=i.performance.now(),h=this.chooseWorkerNode(),u=this.getWorkerInfo(h),k={name:t??g,data:e??{},transferList:s,timestamp:a,workerId:u.id,taskId:r.randomUUID()};this.promiseResponseMap.set(k.taskId,{resolve:o,reject:n,workerNodeKey:h}),!1===this.opts.enableTasksQueue||!0===this.opts.enableTasksQueue&&this.shallExecuteTask(h)?this.executeTask(h,k):this.enqueueTask(h,k)}))}async destroy(){await Promise.all(this.workerNodes.map((async(e,t)=>{await this.destroyWorkerNode(t)}))),this.emitter?.emit(d.destroy,this.info),this.started=!1}async sendKillMessageToWorker(e,t){await new Promise(((s,r)=>{this.registerWorkerMessageListener(e,(e=>{"success"===e.kill?s():"failure"===e.kill&&r(new Error(`Worker ${t} kill message handling failed`))})),this.sendToWorker(e,{kill:!0,workerId:t})}))}setupHook(){}beforeTaskExecutionHook(e,t){if(null!=this.workerNodes[e]?.usage){const s=this.workerNodes[e].usage;++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t)}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name)){const s=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name);++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t)}}afterTaskExecutionHook(e,t){if(null!=this.workerNodes[e]?.usage){const s=this.workerNodes[e].usage;this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t)}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance?.name)){const s=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance?.name);this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t)}}shallUpdateTaskFunctionWorkerUsage(e){const t=this.getWorkerInfo(e);return null!=t&&Array.isArray(t.taskFunctions)&&t.taskFunctions.length>2}updateTaskStatisticsWorkerUsage(e,t){const s=e.tasks;null!=s.executing&&s.executing>0&&--s.executing,null==t.taskError?++s.executed:++s.failed}updateRunTimeWorkerUsage(e,t){null==t.taskError&&v(e.runTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime,t.taskPerformance?.runTime??0)}updateWaitTimeWorkerUsage(e,t){const s=i.performance.now(),r=s-(t.timestamp??s);v(e.waitTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime,r)}updateEluWorkerUsage(e,t){if(null!=t.taskError)return;const s=this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu;v(e.elu.active,s,t.taskPerformance?.elu?.active??0),v(e.elu.idle,s,t.taskPerformance?.elu?.idle??0),s.aggregate&&null!=t.taskPerformance?.elu&&(null!=e.elu.utilization?e.elu.utilization=(e.elu.utilization+t.taskPerformance.elu.utilization)/2:e.elu.utilization=t.taskPerformance.elu.utilization)}chooseWorkerNode(){if(this.shallCreateDynamicWorker()){const e=this.createAndSetupDynamicWorkerNode();if(this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerUsage)return e}return this.workerChoiceStrategyContext.execute()}shallCreateDynamicWorker(){return this.type===k.dynamic&&!this.full&&this.internalBusy()}createAndSetupWorkerNode(){const e=this.createWorker();e.on("online",this.opts.onlineHandler??m),e.on("message",this.opts.messageHandler??m),e.on("error",this.opts.errorHandler??m),e.on("error",(t=>{const s=this.getWorkerNodeKeyByWorker(e),r=this.getWorkerInfo(s);r.ready=!1,this.workerNodes[s].closeChannel(),this.emitter?.emit(d.error,t),!0===this.opts.restartWorkerOnError&&!this.starting&&this.started&&(r.dynamic?this.createAndSetupDynamicWorkerNode():this.createAndSetupWorkerNode()),!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(s)})),e.on("exit",this.opts.exitHandler??m),e.once("exit",(()=>{this.removeWorkerNode(e)}));const t=this.addWorkerNode(e);return this.afterWorkerNodeSetup(t),t}createAndSetupDynamicWorkerNode(){const e=this.createAndSetupWorkerNode();this.registerWorkerMessageListener(e,(e=>{const t=this.getWorkerNodeKeyByWorkerId(e.workerId),s=this.workerNodes[t].usage;(S(C.HARD,e.kill)||S(C.SOFT,e.kill)&&(!1===this.opts.enableTasksQueue&&0===s.tasks.executing||!0===this.opts.enableTasksQueue&&0===s.tasks.executing&&0===this.tasksQueueSize(t)))&&this.destroyWorkerNode(t).catch((e=>{this.emitter?.emit(d.error,e)}))}));const t=this.getWorkerInfo(e);return this.sendToWorker(e,{checkActive:!0,workerId:t.id}),t.dynamic=!0,(this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerReady||this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerUsage)&&(t.ready=!0),this.checkAndEmitDynamicWorkerCreationEvents(),e}afterWorkerNodeSetup(e){this.registerWorkerMessageListener(e,this.workerListener()),this.sendStartupMessageToWorker(e),this.sendStatisticsMessageToWorker(e),!0===this.opts.enableTasksQueue&&(this.workerNodes[e].onEmptyQueue=this.taskStealingOnEmptyQueue.bind(this),this.workerNodes[e].onBackPressure=this.tasksStealingOnBackPressure.bind(this))}sendStatisticsMessageToWorker(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate},workerId:this.getWorkerInfo(e).id})}redistributeQueuedTasks(e){for(;this.tasksQueueSize(e)>0;){let t,s=1/0;for(const[r,i]of this.workerNodes.entries())if(i.info.ready&&r!==e){if(0===i.usage.tasks.queued){t=r;break}i.usage.tasks.queued<s&&(s=i.usage.tasks.queued,t=r)}if(null!=t){const s=this.workerNodes[t],r={...this.dequeueTask(e),workerId:s.info.id};this.shallExecuteTask(t)?this.executeTask(t,r):this.enqueueTask(t,r)}}}updateTaskStolenStatisticsWorkerUsage(e,t){const s=this.workerNodes[e];if(null!=s?.usage&&++s.usage.tasks.stolen,this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=s.getTaskFunctionWorkerUsage(t)){++s.getTaskFunctionWorkerUsage(t).tasks.stolen}}taskStealingOnEmptyQueue(e){const t=this.getWorkerNodeKeyByWorkerId(e),s=this.workerNodes[t],r=this.workerNodes.slice().sort(((e,t)=>t.usage.tasks.queued-e.usage.tasks.queued));for(const i of r){if(0===i.usage.tasks.queued)break;if(i.info.ready&&i.info.id!==e&&i.usage.tasks.queued>0){const e={...i.popTask(),workerId:s.info.id};this.shallExecuteTask(t)?this.executeTask(t,e):this.enqueueTask(t,e),this.updateTaskStolenStatisticsWorkerUsage(t,e.name);break}}}tasksStealingOnBackPressure(e){if(this.opts.tasksQueueOptions?.size<=1)return;const t=this.workerNodes[this.getWorkerNodeKeyByWorkerId(e)],s=this.workerNodes.slice().sort(((e,t)=>e.usage.tasks.queued-t.usage.tasks.queued));for(const[r,i]of s.entries())if(t.usage.tasks.queued>0&&i.info.ready&&i.info.id!==e&&i.usage.tasks.queued<this.opts.tasksQueueOptions?.size-1){const e={...t.popTask(),workerId:i.info.id};this.shallExecuteTask(r)?this.executeTask(r,e):this.enqueueTask(r,e),this.updateTaskStolenStatisticsWorkerUsage(r,e.name)}}workerListener(){return e=>{this.checkMessageWorkerId(e),null!=e.ready&&null!=e.taskFunctions?this.handleWorkerReadyResponse(e):null!=e.taskId?this.handleTaskExecutionResponse(e):null!=e.taskFunctions&&(this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId)).taskFunctions=e.taskFunctions)}}handleWorkerReadyResponse(e){if(!1===e.ready)throw new Error(`Worker ${e.workerId} failed to initialize`);const t=this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId));t.ready=e.ready,t.taskFunctions=e.taskFunctions,null!=this.emitter&&this.ready&&this.emitter.emit(d.ready,this.info)}handleTaskExecutionResponse(e){const{taskId:t,taskError:s,data:r}=e,i=this.promiseResponseMap.get(t);if(null!=i){null!=s?(this.emitter?.emit(d.taskError,s),i.reject(s.message)):i.resolve(r);const o=i.workerNodeKey;this.afterTaskExecutionHook(o,e),this.promiseResponseMap.delete(t),!0===this.opts.enableTasksQueue&&this.tasksQueueSize(o)>0&&this.workerNodes[o].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&this.executeTask(o,this.dequeueTask(o)),this.workerChoiceStrategyContext.update(o)}}checkAndEmitTaskExecutionEvents(){this.busy&&this.emitter?.emit(d.busy,this.info)}checkAndEmitTaskQueuingEvents(){this.hasBackPressure()&&this.emitter?.emit(d.backPressure,this.info)}checkAndEmitDynamicWorkerCreationEvents(){this.type===k.dynamic&&this.full&&this.emitter?.emit(d.full,this.info)}getWorkerInfo(e){return this.workerNodes[e]?.info}addWorkerNode(e){const t=new L(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 node added not found");return s}removeWorkerNode(e){const t=this.getWorkerNodeKeyByWorker(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategyContext.remove(t))}hasWorkerNodeBackPressure(e){return!0===this.opts.enableTasksQueue&&this.workerNodes[e].hasBackPressure()}hasBackPressure(){return!0===this.opts.enableTasksQueue&&-1===this.workerNodes.findIndex((e=>!e.hasBackPressure()))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(e,t,t.transferList),this.checkAndEmitTaskExecutionEvents()}enqueueTask(e,t){const s=this.workerNodes[e].enqueueTask(t);return this.checkAndEmitTaskQueuingEvents(),s}dequeueTask(e){return this.workerNodes[e].dequeueTask()}tasksQueueSize(e){return this.workerNodes[e].tasksQueueSize()}flushTasksQueue(e){for(;this.tasksQueueSize(e)>0;)this.executeTask(e,this.dequeueTask(e));this.workerNodes[e].clearTasksQueue()}flushTasksQueues(){for(const[e]of this.workerNodes.entries())this.flushTasksQueue(e)}}class _ extends V{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}setupHook(){s.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return s.isPrimary}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e],s=t.worker,r=new Promise((e=>{s.on("exit",(()=>{e()}))}));s.on("disconnect",(()=>{s.kill()})),await this.sendKillMessageToWorker(e,t.info.id),s.disconnect(),await r}sendToWorker(e,t){this.workerNodes[e].worker.send(t)}sendStartupMessageToWorker(e){this.sendToWorker(e,{ready:!1,workerId:this.workerNodes[e].info.id})}registerWorkerMessageListener(e,t){this.workerNodes[e].worker.on("message",t)}createWorker(){return s.fork(this.opts.env)}get type(){return k.fixed}get worker(){return l.cluster}get busy(){return this.internalBusy()}}class j extends V{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}isMain(){return t.isMainThread}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e],s=t.worker,r=new Promise((e=>{s.on("exit",(()=>{e()}))}));await this.sendKillMessageToWorker(e,t.info.id),t.closeChannel(),await s.terminate(),await r}sendToWorker(e,t,s){this.workerNodes[e].messageChannel.port1.postMessage(t,s)}sendStartupMessageToWorker(e){const t=this.workerNodes[e],s=t.worker,r=t.messageChannel.port2;s.postMessage({ready:!1,workerId:t.info.id,port:r},[r])}registerWorkerMessageListener(e,t){this.workerNodes[e].messageChannel.port1.on("message",t)}createWorker(){return new t.Worker(this.filePath,{env:t.SHARE_ENV,...this.opts.workerOptions})}get type(){return k.fixed}get worker(){return l.thread}get busy(){return this.internalBusy()}}const H=6e4,$={killBehavior:C.SOFT,maxInactiveTime:H,killHandler:m};class G extends a.AsyncResource{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,s,r,i=$){if(super(e),this.isMain=t,this.mainWorker=s,this.opts=i,null==this.isMain)throw new Error("isMain parameter is mandatory");this.checkTaskFunctions(r),this.checkWorkerOptions(this.opts),this.isMain||this.getMainWorker().on("message",this.handleReadyMessage.bind(this))}checkWorkerOptions(e){this.opts={...$,...e},delete this.opts.async}checkValidTaskFunction(e,t){if("string"!=typeof e)throw new TypeError("A taskFunctions parameter object key is not a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("A taskFunctions parameter object key is an empty string");if("function"!=typeof t)throw new TypeError("A taskFunctions parameter object value is not a function")}checkTaskFunctions(e){if(null==e)throw new Error("taskFunctions parameter is mandatory");if(this.taskFunctions=new Map,"function"==typeof e){const t=e.bind(this);this.taskFunctions.set(g,t),this.taskFunctions.set("string"==typeof e.name&&e.name.trim().length>0?e.name:"fn1",t)}else{if(!x(e))throw new TypeError("taskFunctions parameter is not a function or a plain object");{let t=!0;for(const[s,r]of Object.entries(e)){this.checkValidTaskFunction(s,r);const e=r.bind(this);t&&(this.taskFunctions.set(g,e),t=!1),this.taskFunctions.set(s,e)}if(t)throw new Error("taskFunctions parameter object is empty")}}}hasTaskFunction(e){return this.checkTaskFunctionName(e),this.taskFunctions.has(e)}addTaskFunction(e,t){if(this.checkTaskFunctionName(e),e===g)throw new Error("Cannot add a task function with the default reserved name");if("function"!=typeof t)throw new TypeError("fn parameter is not a function");try{const s=t.bind(this);return this.taskFunctions.get(e)===this.taskFunctions.get(g)&&this.taskFunctions.set(g,s),this.taskFunctions.set(e,s),this.sendTaskFunctionsListToMainWorker(),!0}catch{return!1}}removeTaskFunction(e){if(this.checkTaskFunctionName(e),e===g)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(g))throw new Error("Cannot remove the task function used as the default task function");const t=this.taskFunctions.delete(e);return this.sendTaskFunctionsListToMainWorker(),t}listTaskFunctions(){const e=[...this.taskFunctions.keys()];let t=g;for(const[e,s]of this.taskFunctions)if(e!==g&&s===this.taskFunctions.get(g)){t=e;break}return[e[e.indexOf(g)],t,...e.filter((e=>e!==g&&e!==t))]}setDefaultTaskFunction(e){if(this.checkTaskFunctionName(e),e===g)throw new Error("Cannot set the default task function reserved name as the default task function");if(!this.taskFunctions.has(e))throw new Error("Cannot set the default task function to a non-existing task function");try{return this.taskFunctions.set(g,this.taskFunctions.get(e)),!0}catch{return!1}}checkTaskFunctionName(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("name parameter is an empty string")}messageListener(e){this.checkMessageWorkerId(e),null!=e.statistics?this.statistics=e.statistics:null!=e.checkActive?e.checkActive?this.startCheckActive():this.stopCheckActive():null!=e.taskId&&null!=e.data?this.run(e):!0===e.kill&&this.handleKillMessage(e)}handleKillMessage(e){if(this.stopCheckActive(),E(this.opts.killHandler))(this.opts.killHandler?.()).then((()=>(this.sendToMainWorker({kill:"success",workerId:this.id}),null))).catch((()=>{this.sendToMainWorker({kill:"failure",workerId:this.id})})).finally((()=>{this.emitDestroy()})).catch(m);else try{this.opts.killHandler?.(),this.sendToMainWorker({kill:"success",workerId:this.id})}catch{this.sendToMainWorker({kill:"failure",workerId:this.id})}finally{this.emitDestroy()}}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Message worker id is not set");if(null!=e.workerId&&e.workerId!==this.id)throw new Error(`Message worker id ${e.workerId} does not match the worker id ${this.id}`)}startCheckActive(){this.lastTaskTimestamp=i.performance.now(),this.activeInterval=setInterval(this.checkActive.bind(this),(this.opts.maxInactiveTime??H)/2)}stopCheckActive(){null!=this.activeInterval&&(clearInterval(this.activeInterval),delete this.activeInterval)}checkActive(){i.performance.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??H)&&this.sendToMainWorker({kill:this.opts.killBehavior,workerId:this.id})}getMainWorker(){if(null==this.mainWorker)throw new Error("Main worker not set");return this.mainWorker}sendTaskFunctionsListToMainWorker(){this.sendToMainWorker({taskFunctions:this.listTaskFunctions(),workerId:this.id})}handleError(e){return e instanceof Error?e.message:e}run(e){const{name:t,taskId:s,data:r}=e,i=this.taskFunctions.get(t??g);null!=i?E(i)?this.runInAsyncScope(this.runAsync.bind(this),this,i,e):this.runInAsyncScope(this.runSync.bind(this),this,i,e):this.sendToMainWorker({taskError:{name:t,message:`Task function '${t}' not found`,data:r},workerId:this.id,taskId:s})}runSync(e,t){const{name:s,taskId:r,data:i}=t;try{let t=this.beginTaskPerformance(s);const o=e(i);t=this.endTaskPerformance(t),this.sendToMainWorker({data:o,taskPerformance:t,workerId:this.id,taskId:r})}catch(e){const t=this.handleError(e);this.sendToMainWorker({taskError:{name:s,message:t,data:i},workerId:this.id,taskId:r})}finally{this.updateLastTaskTimestamp()}}runAsync(e,t){const{name:s,taskId:r,data:i}=t;let o=this.beginTaskPerformance(s);e(i).then((e=>(o=this.endTaskPerformance(o),this.sendToMainWorker({data:e,taskPerformance:o,workerId:this.id,taskId:r}),null))).catch((e=>{const t=this.handleError(e);this.sendToMainWorker({taskError:{name:s,message:t,data:i},workerId:this.id,taskId:r})})).finally((()=>{this.updateLastTaskTimestamp()})).catch(m)}beginTaskPerformance(e){return this.checkStatistics(),{name:e??g,timestamp:i.performance.now(),...this.statistics.elu&&{elu:i.performance.eventLoopUtilization()}}}endTaskPerformance(e){return this.checkStatistics(),{...e,...this.statistics.runTime&&{runTime:i.performance.now()-e.timestamp},...this.statistics.elu&&{elu:i.performance.eventLoopUtilization(e.elu)}}}checkStatistics(){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set")}updateLastTaskTimestamp(){null!=this.activeInterval&&(this.lastTaskTimestamp=i.performance.now())}}exports.ClusterWorker=class extends G{constructor(e,t={}){super("worker-cluster-pool:poolifier",s.isPrimary,s.worker,e,t)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready)try{this.getMainWorker().on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctions:this.listTaskFunctions(),workerId:this.id})}catch{this.sendToMainWorker({ready:!1,taskFunctions:this.listTaskFunctions(),workerId:this.id})}}get id(){return this.getMainWorker().id}sendToMainWorker(e){this.getMainWorker().send(e)}},exports.DynamicClusterPool=class extends _{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return k.dynamic}get busy(){return this.full&&this.internalBusy()}},exports.DynamicThreadPool=class extends j{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return k.dynamic}get busy(){return this.full&&this.internalBusy()}},exports.FixedClusterPool=_,exports.FixedThreadPool=j,exports.KillBehaviors=C,exports.Measurements=R,exports.PoolEvents=d,exports.PoolTypes=k,exports.ThreadWorker=class extends G{port;constructor(e,s={}){super("worker-thread-pool:poolifier",t.isMainThread,t.parentPort,e,s)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready&&null!=e.port)try{this.port=e.port,this.port.on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctions:this.listTaskFunctions(),workerId:this.id})}catch{this.sendToMainWorker({ready:!1,taskFunctions:this.listTaskFunctions(),workerId:this.id})}}handleKillMessage(e){super.handleKillMessage(e),this.port?.unref(),this.port?.close()}get id(){return t.threadId}sendToMainWorker(e){this.port.postMessage(e)}handleError(e){return e}},exports.WorkerChoiceStrategies=I,exports.WorkerTypes=l,exports.availableParallelism=()=>{let e=1;try{e=u.availableParallelism()}catch{const t=u.cpus();Array.isArray(t)&&t.length>0&&(e=t.length)}return e};
package/lib/index.mjs CHANGED
@@ -1 +1 @@
1
- import{EventEmitter as e}from"node:events";import{MessageChannel as t,isMainThread as s,Worker as r,SHARE_ENV as i,parentPort as o,threadId as n}from"node:worker_threads";import a from"node:cluster";import{webcrypto as h,randomUUID as u}from"node:crypto";import{performance as k}from"node:perf_hooks";import{existsSync as c}from"node:fs";import*as d from"node:os";import{cpus as l}from"node:os";import{AsyncResource as g}from"node:async_hooks";const m=Object.freeze({fixed:"fixed",dynamic:"dynamic"});class p extends e{}const w=Object.freeze({ready:"ready",busy:"busy",full:"full",destroy:"destroy",error:"error",taskError:"taskError",backPressure:"backPressure"}),y="default",f=Object.freeze((()=>{})),T={choiceRetries:6,runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},W={aggregate:!1,average:!1,median:!1},N=()=>{let e=1;try{e=d.availableParallelism()}catch{const t=d.cpus();Array.isArray(t)&&t.length>0&&(e=t.length)}return e},x=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,S=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},E=(e,t=2)=>{const s=Math.pow(10,t);return Math.round(e*s*(1+Number.EPSILON))/s},v=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),b=(e,t)=>t===e,I=e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name,C=(e,t,s)=>{t.aggregate&&(e.aggregate=(e.aggregate??0)+s,e.minimum=Math.min(s,e.minimum??1/0),e.maximum=Math.max(s,e.maximum??-1/0),(t.average||t.median)&&null!=s&&(e.history.push(s),t.average&&(e.average=x(e.history)),t.median&&(e.median=S(e.history))))},R=()=>h.getRandomValues(new Uint32Array(1))[0]/4294967296,z=Object.freeze({SOFT:"SOFT",HARD:"HARD"}),O=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"}),Q=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"});class F{pool;opts;nextWorkerNodeKey=0;previousWorkerNodeKey=0;strategyPolicy={dynamicWorkerUsage:!1,dynamicWorkerReady:!0};taskStatisticsRequirements={runTime:W,waitTime:W,elu:W};constructor(e,t=T){this.pool=e,this.opts=t,this.opts={...T,...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={...T,...e},this.setTaskStatisticsRequirements(this.opts)}isWorkerNodeReady(e){return this.pool.workerNodes[e].info.ready}hasWorkerNodeBackPressure(e){return this.pool.hasWorkerNodeBackPressure(e)}isWorkerNodeEligible(e){return this.isWorkerNodeReady(e)&&!this.hasWorkerNodeBackPressure(e)}getWorkerTaskRunTime(e){return this.taskStatisticsRequirements.runTime.median?this.pool.workerNodes[e].usage.runTime?.median??0:this.pool.workerNodes[e].usage.runTime?.average??0}getWorkerTaskWaitTime(e){return this.taskStatisticsRequirements.waitTime.median?this.pool.workerNodes[e].usage.waitTime?.median??0:this.pool.workerNodes[e].usage.waitTime?.average??0}getWorkerTaskElu(e){return this.taskStatisticsRequirements.elu.median?this.pool.workerNodes[e].usage.elu.active?.median??0:this.pool.workerNodes[e].usage.elu.active?.average??0}checkNextWorkerNodeEligibility(e){this.isWorkerNodeEligible(this.nextWorkerNodeKey)||(this.nextWorkerNodeKey=void 0,this.previousWorkerNodeKey=e??this.previousWorkerNodeKey)}computeDefaultWorkerWeight(){let e=0;for(const t of l()){const s=t.speed.toString().length-1;e+=1/(t.speed/Math.pow(10,s))*Math.pow(10,s)}return Math.round(e/l().length)}}class M extends F{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:W,elu:{aggregate:!0,average:!0,median:!1}};workersVirtualTaskEndTimestamp=[];constructor(e,t=T){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.workersVirtualTaskEndTimestamp=[],!0}update(e){return this.computeWorkerVirtualTaskEndTimestamp(e),!0}choose(){return this.nextWorkerNodeKey=this.fairShareNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(e){return this.workersVirtualTaskEndTimestamp.splice(e,1),!0}fairShareNextWorkerNodeKey(){let e,t=1/0;for(const[s]of this.pool.workerNodes.entries()){null==this.workersVirtualTaskEndTimestamp[s]&&this.computeWorkerVirtualTaskEndTimestamp(s);const r=this.workersVirtualTaskEndTimestamp[s];this.isWorkerNodeEligible(s)&&r<t&&(t=r,e=s)}return e}computeWorkerVirtualTaskEndTimestamp(e){this.workersVirtualTaskEndTimestamp[e]=this.getWorkerVirtualTaskEndTimestamp(e,this.getWorkerVirtualTaskStartTimestamp(e))}getWorkerVirtualTaskEndTimestamp(e,t){return t+(this.opts.measurement===Q.elu?this.getWorkerTaskElu(e):this.getWorkerTaskRunTime(e))}getWorkerVirtualTaskStartTimestamp(e){return Math.max(performance.now(),this.workersVirtualTaskEndTimestamp[e]??-1/0)}}class K extends F{roundId=0;roundWeights;defaultWorkerWeight;constructor(e,t=T){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight(),this.roundWeights=this.getRoundWeights()}reset(){return this.resetWorkerNodeKeyProperties(),this.roundId=0,!0}update(){return!0}choose(){let e,t;for(let s=this.roundId;s<this.roundWeights.length;s++){e=s;for(let e=this.nextWorkerNodeKey??this.previousWorkerNodeKey;e<this.pool.workerNodes.length;e++){const r=this.opts.weights?.[e]??this.defaultWorkerWeight;if(this.isWorkerNodeEligible(e)&&r>=this.roundWeights[s]){t=e;break}}}this.roundId=e,null==t&&(this.previousWorkerNodeKey=this.nextWorkerNodeKey??this.previousWorkerNodeKey),this.nextWorkerNodeKey=t;const s=this.nextWorkerNodeKey;return this.nextWorkerNodeKey===this.pool.workerNodes.length-1?(this.nextWorkerNodeKey=0,this.roundId=this.roundId===this.roundWeights.length-1?0:this.roundId+1):this.nextWorkerNodeKey=(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,s}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1,this.roundId=this.roundId===this.roundWeights.length-1?0:this.roundId+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 F{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:W};constructor(e,t=T){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.nextWorkerNodeKey=this.leastBusyNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastBusyNextWorkerNodeKey(){let e,t=1/0;for(const[s,r]of this.pool.workerNodes.entries()){const i=(r.usage.runTime?.aggregate??0)+(r.usage.waitTime?.aggregate??0);if(this.isWorkerNodeEligible(s)&&0===i){e=s;break}this.isWorkerNodeEligible(s)&&i<t&&(t=i,e=s)}return e}}class P extends F{constructor(e,t=T){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.nextWorkerNodeKey=this.leastUsedNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastUsedNextWorkerNodeKey(){let e,t=1/0;for(const[s,r]of this.pool.workerNodes.entries()){const i=r.usage.tasks,o=i.executed+i.executing+i.queued;if(this.isWorkerNodeEligible(s)&&0===o){e=s;break}this.isWorkerNodeEligible(s)&&o<t&&(t=o,e=s)}return e}}class A extends F{taskStatisticsRequirements={runTime:W,waitTime:W,elu:{aggregate:!0,average:!1,median:!1}};constructor(e,t=T){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.nextWorkerNodeKey=this.leastEluNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastEluNextWorkerNodeKey(){let e,t=1/0;for(const[s,r]of this.pool.workerNodes.entries()){const i=r.usage,o=i.elu?.active?.aggregate??0;if(this.isWorkerNodeEligible(s)&&0===o){e=s;break}this.isWorkerNodeEligible(s)&&o<t&&(t=o,e=s)}return e}}class U extends F{constructor(e,t=T){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.resetWorkerNodeKeyProperties(),!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;return this.roundRobinNextWorkerNodeKey(),this.checkNextWorkerNodeEligibility(e),e}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=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 B extends F{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:W,elu:W};defaultWorkerWeight;workerVirtualTaskRunTime=0;constructor(e,t=T){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight()}reset(){return this.resetWorkerNodeKeyProperties(),this.workerVirtualTaskRunTime=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;return this.weightedRoundRobinNextWorkerNodeKey(),this.checkNextWorkerNodeEligibility(e),e}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1),this.workerVirtualTaskRunTime=0),!0}weightedRoundRobinNextWorkerNodeKey(){const e=this.workerVirtualTaskRunTime;return e<(this.opts.weights?.[this.nextWorkerNodeKey??this.previousWorkerNodeKey]??this.defaultWorkerWeight)?this.workerVirtualTaskRunTime=e+this.getWorkerTaskRunTime(this.nextWorkerNodeKey??this.previousWorkerNodeKey):(this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,this.workerVirtualTaskRunTime=0),this.nextWorkerNodeKey}}class D{workerChoiceStrategy;opts;workerChoiceStrategies;choiceRetriesCount=0;constructor(e,t=O.ROUND_ROBIN,s=T){this.workerChoiceStrategy=t,this.opts=s,this.opts={...T,...s},this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[O.ROUND_ROBIN,new(U.bind(this))(e,s)],[O.LEAST_USED,new(P.bind(this))(e,s)],[O.LEAST_BUSY,new(q.bind(this))(e,s)],[O.LEAST_ELU,new(A.bind(this))(e,s)],[O.FAIR_SHARE,new(M.bind(this))(e,s)],[O.WEIGHTED_ROUND_ROBIN,new(B.bind(this))(e,s)],[O.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).choose();if(null==e&&this.choiceRetriesCount<this.opts.choiceRetries)return this.choiceRetriesCount++,this.execute();if(null==e)throw new Error(`Worker node key chosen is null or undefined after ${this.choiceRetriesCount} retries`);return this.choiceRetriesCount=0,e}remove(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).remove(e)}setOptions(e){this.opts={...T,...e};for(const t of this.workerChoiceStrategies.values())t.setOptions(e)}}class L 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 L(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 _{value;next;prev;constructor(e){this.value=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?this.head=void 0:this.tail.next=void 0,--this.size,e?.value}shift(){if(null==this.head)return;const e=this.head;return this.head=this.head.next,null==this.head?this.tail=void 0:this.head.prev=void 0,--this.size,e?.value}peekFirst(){return this.head?.value}peekLast(){return this.tail?.value}clear(){this.head=void 0,this.tail=void 0,this.size=0,this.maxSize=0}[Symbol.iterator](){let e=this.head;return{next:()=>{if(null==e)return{value:void 0,done:!0};const t={value:e.value,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.value,done:!1};return e=e.prev,t}}}}}incrementSize(){return++this.size,this.size>this.maxSize&&(this.maxSize=this.size),this.size}}const j=Object.freeze({thread:"thread",cluster:"cluster"});class H{worker;info;usage;messageChannel;tasksQueueBackPressureSize;onBackPressure;onEmptyQueue;tasksQueue;onEmptyQueueCount;taskFunctionsUsage;constructor(e,s,r){if(null==e)throw new TypeError("Cannot construct a worker node without a worker");if(null==s)throw new TypeError("Cannot construct a worker node without a worker type");if(null==r)throw new TypeError("Cannot construct a worker node without a tasks queue back pressure size");if(!Number.isSafeInteger(r))throw new TypeError("Cannot construct a worker node with a tasks queue back pressure size that is not an integer");this.worker=e,this.info=this.initWorkerInfo(e,s),this.usage=this.initWorkerUsage(),s===j.thread&&(this.messageChannel=new t),this.tasksQueueBackPressureSize=r,this.tasksQueue=new V,this.onEmptyQueueCount=0,this.taskFunctionsUsage=new Map}tasksQueueSize(){return this.tasksQueue.size}enqueueTask(e){const t=this.tasksQueue.push(e);return null!=this.onBackPressure&&this.hasBackPressure()&&this.onBackPressure(this.info.id),t}unshiftTask(e){const t=this.tasksQueue.unshift(e);return null!=this.onBackPressure&&this.hasBackPressure()&&this.onBackPressure(this.info.id),t}dequeueTask(){const e=this.tasksQueue.shift();return null!=this.onEmptyQueue&&0===this.tasksQueue.size&&this.startOnEmptyQueue().catch(f),e}popTask(){const e=this.tasksQueue.pop();return null!=this.onEmptyQueue&&0===this.tasksQueue.size&&this.startOnEmptyQueue().catch(f),e}clearTasksQueue(){this.tasksQueue.clear()}hasBackPressure(){return this.tasksQueue.size>=this.tasksQueueBackPressureSize}resetUsage(){this.usage=this.initWorkerUsage(),this.taskFunctionsUsage.clear()}closeChannel(){null!=this.messageChannel&&(this.messageChannel?.port1.unref(),this.messageChannel?.port2.unref(),this.messageChannel?.port1.close(),this.messageChannel?.port2.close(),delete this.messageChannel)}getTaskFunctionWorkerUsage(e){if(!Array.isArray(this.info.taskFunctions))throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function names list is not yet defined`);if(Array.isArray(this.info.taskFunctions)&&this.info.taskFunctions.length<3)throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function names list has less than 3 elements`);return e===y&&(e=this.info.taskFunctions[1]),this.taskFunctionsUsage.has(e)||this.taskFunctionsUsage.set(e,this.initTaskFunctionWorkerUsage(e)),this.taskFunctionsUsage.get(e)}async startOnEmptyQueue(){this.onEmptyQueueCount>0&&(this.usage.tasks.executing>0||this.tasksQueue.size>0)?this.onEmptyQueueCount=0:(this.onEmptyQueue(this.info.id),++this.onEmptyQueueCount,await(async e=>{await new Promise((t=>{setTimeout(t,e)}))})(((e=0,t=100)=>{const s=Math.pow(2,e)*t;return s+.2*s*R()})(this.onEmptyQueueCount)),await this.startOnEmptyQueue())}initWorkerInfo(e,t){return{id:this.getWorkerId(e,t),type:t,dynamic:!1,ready:!1}}initWorkerUsage(){const e=()=>this.tasksQueue.size,t=()=>this.tasksQueue.maxSize;return{tasks:{executed:0,executing:0,get queued(){return e()},get maxQueued(){return t()},stolen:0,failed:0},runTime:{history:new L},waitTime:{history:new L},elu:{idle:{history:new L},active:{history:new L}}}}initTaskFunctionWorkerUsage(e){const t=()=>{let t=0;for(const s of this.tasksQueue)(s.name===y&&e===this.info.taskFunctions[1]||s.name!==y&&e===s.name)&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},stolen:0,failed:0},runTime:{history:new L},waitTime:{history:new L},elu:{idle:{history:new L},active:{history:new L}}}}getWorkerId(e,t){return t===j.thread?e.threadId:t===j.cluster?e.id:void 0}}class ${numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;max;starting;started;startTimestamp;constructor(e,t,s){if(this.numberOfWorkers=e,this.filePath=t,this.opts=s,!this.isMain())throw new Error("Cannot start a pool from a worker with the same type as the pool");this.checkNumberOfWorkers(this.numberOfWorkers),this.checkFilePath(this.filePath),this.checkPoolOptions(this.opts),this.chooseWorkerNode=this.chooseWorkerNode.bind(this),this.executeTask=this.executeTask.bind(this),this.enqueueTask=this.enqueueTask.bind(this),!0===this.opts.enableEvents&&(this.emitter=new p),this.workerChoiceStrategyContext=new D(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook(),this.starting=!0,this.startPool(),this.starting=!1,this.started=!0,this.startTimestamp=k.now()}checkFilePath(e){if(null==e||"string"!=typeof e||"string"==typeof e&&0===e.trim().length)throw new Error("Please specify a file with a worker implementation");if(!c(e))throw new Error(`Cannot find the worker file '${e}'`)}checkNumberOfWorkers(e){if(null==e)throw new Error("Cannot instantiate a pool without specifying the number of workers");if(!Number.isSafeInteger(e))throw new TypeError("Cannot instantiate a pool with a non safe integer number of workers");if(e<0)throw new RangeError("Cannot instantiate a pool with a negative number of workers");if(this.type===m.fixed&&0===e)throw new RangeError("Cannot instantiate a fixed pool with zero worker")}checkDynamicPoolSize(e,t){if(this.type===m.dynamic){if(null==t)throw new TypeError("Cannot instantiate a dynamic pool without specifying the maximum pool size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot instantiate a dynamic pool with a non safe integer maximum pool size");if(e>t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size");if(0===t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size equal to zero");if(e===t)throw new RangeError("Cannot instantiate a dynamic pool with a minimum pool size equal to the maximum pool size. Use a fixed pool instead")}}checkPoolOptions(e){if(!v(e))throw new TypeError("Invalid pool options: must be a plain object");this.opts.workerChoiceStrategy=e.workerChoiceStrategy??O.ROUND_ROBIN,this.checkValidWorkerChoiceStrategy(this.opts.workerChoiceStrategy),this.opts.workerChoiceStrategyOptions={...T,...e.workerChoiceStrategyOptions},this.checkValidWorkerChoiceStrategyOptions(this.opts.workerChoiceStrategyOptions),this.opts.restartWorkerOnError=e.restartWorkerOnError??!0,this.opts.enableEvents=e.enableEvents??!0,this.opts.enableTasksQueue=e.enableTasksQueue??!1,this.opts.enableTasksQueue&&(this.checkValidTasksQueueOptions(e.tasksQueueOptions),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e.tasksQueueOptions))}checkValidWorkerChoiceStrategy(e){if(!Object.values(O).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)}checkValidWorkerChoiceStrategyOptions(e){if(!v(e))throw new TypeError("Invalid worker choice strategy options: must be a plain object");if(null!=e.choiceRetries&&!Number.isSafeInteger(e.choiceRetries))throw new TypeError("Invalid worker choice strategy options: choice retries must be an integer");if(null!=e.choiceRetries&&e.choiceRetries<0)throw new RangeError(`Invalid worker choice strategy options: choice retries '${e.choiceRetries}' 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(Q).includes(e.measurement))throw new Error(`Invalid worker choice strategy options: invalid measurement '${e.measurement}'`)}checkValidTasksQueueOptions(e){if(null!=e&&!v(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?.queueMaxSize)throw new Error("Invalid tasks queue options: queueMaxSize is deprecated, please use size instead");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`)}startPool(){for(;this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.numberOfWorkers;)this.createAndSetupWorkerNode()}get info(){return{version:"2.6.36",type:this.type,worker:this.worker,ready:this.ready,strategy:this.opts.workerChoiceStrategy,minSize:this.minSize,maxSize:this.maxSize,...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{utilization:E(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:E(Math.min(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:E(Math.max(...this.workerNodes.map((e=>e.usage.runTime?.maximum??-1/0)))),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.average&&{average:E(x(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&{median:E(S(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:E(Math.min(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:E(Math.max(...this.workerNodes.map((e=>e.usage.waitTime?.maximum??-1/0)))),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.average&&{average:E(x(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.waitTime.history)),[])))},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&{median:E(S(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=(k.now()-this.startTimestamp)*this.maxSize;return(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)+this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0))/e}get minSize(){return this.numberOfWorkers}get maxSize(){return this.max??this.numberOfWorkers}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Worker message received without worker id");if(null!=e.workerId&&-1===this.getWorkerNodeKeyByWorkerId(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKeyByWorker(e){return this.workerNodes.findIndex((t=>t.worker===e))}getWorkerNodeKeyByWorkerId(e){return this.workerNodes.findIndex((t=>t.info.id===e))}setWorkerChoiceStrategy(e,t){this.checkValidWorkerChoiceStrategy(e),this.opts.workerChoiceStrategy=e,this.workerChoiceStrategyContext.setWorkerChoiceStrategy(this.opts.workerChoiceStrategy),null!=t&&this.setWorkerChoiceStrategyOptions(t);for(const[e,t]of this.workerNodes.entries())t.resetUsage(),this.sendStatisticsMessageToWorker(e)}setWorkerChoiceStrategyOptions(e){this.checkValidWorkerChoiceStrategyOptions(e),this.opts.workerChoiceStrategyOptions={...T,...e},this.workerChoiceStrategyContext.setOptions(this.opts.workerChoiceStrategyOptions)}enableTasksQueue(e,t){!0!==this.opts.enableTasksQueue||e||this.flushTasksQueues(),this.opts.enableTasksQueue=e,this.setTasksQueueOptions(t)}setTasksQueueOptions(e){!0===this.opts.enableTasksQueue?(this.checkValidTasksQueueOptions(e),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e),this.setTasksQueueMaxSize(this.opts.tasksQueueOptions.size)):null!=this.opts.tasksQueueOptions&&delete this.opts.tasksQueueOptions}setTasksQueueMaxSize(e){for(const t of this.workerNodes)t.tasksQueueBackPressureSize=e}buildTasksQueueOptions(e){return{size:Math.pow(this.maxSize,2),concurrency:1,...e}}get full(){return this.workerNodes.length>=this.maxSize}internalBusy(){return!0===this.opts.enableTasksQueue?-1===this.workerNodes.findIndex((e=>e.info.ready&&e.usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency)):-1===this.workerNodes.findIndex((e=>e.info.ready&&0===e.usage.tasks.executing))}listTaskFunctions(){for(const e of this.workerNodes)if(Array.isArray(e.info.taskFunctions)&&e.info.taskFunctions.length>0)return e.info.taskFunctions;return[]}async execute(e,t,s){return await new Promise(((r,i)=>{if(!this.started)return void i(new Error("Cannot execute a task on destroyed pool"));if(null!=t&&"string"!=typeof t)return void i(new TypeError("name argument must be a string"));if(null!=t&&"string"==typeof t&&0===t.trim().length)return void i(new TypeError("name argument must not be an empty string"));if(null!=s&&!Array.isArray(s))return void i(new TypeError("transferList argument must be an array"));const o=k.now(),n=this.chooseWorkerNode(),a=this.getWorkerInfo(n),h={name:t??y,data:e??{},transferList:s,timestamp:o,workerId:a.id,taskId:u()};this.promiseResponseMap.set(h.taskId,{resolve:r,reject:i,workerNodeKey:n}),!1===this.opts.enableTasksQueue||!0===this.opts.enableTasksQueue&&0===this.tasksQueueSize(n)&&this.workerNodes[n].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency?this.executeTask(n,h):this.enqueueTask(n,h)}))}async destroy(){await Promise.all(this.workerNodes.map((async(e,t)=>{await this.destroyWorkerNode(t)}))),this.emitter?.emit(w.destroy,this.info),this.started=!1}async sendKillMessageToWorker(e,t){await new Promise(((s,r)=>{this.registerWorkerMessageListener(e,(e=>{"success"===e.kill?s():"failure"===e.kill&&r(new Error(`Worker ${t} kill message handling failed`))})),this.sendToWorker(e,{kill:!0,workerId:t})}))}setupHook(){}beforeTaskExecutionHook(e,t){if(null!=this.workerNodes[e]?.usage){const s=this.workerNodes[e].usage;++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t)}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name)){const s=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name);++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t)}}afterTaskExecutionHook(e,t){if(null!=this.workerNodes[e]?.usage){const s=this.workerNodes[e].usage;this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t)}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance?.name)){const s=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance?.name);this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t)}}shallUpdateTaskFunctionWorkerUsage(e){const t=this.getWorkerInfo(e);return null!=t&&Array.isArray(t.taskFunctions)&&t.taskFunctions.length>2}updateTaskStatisticsWorkerUsage(e,t){const s=e.tasks;null!=s.executing&&s.executing>0&&--s.executing,null==t.taskError?++s.executed:++s.failed}updateRunTimeWorkerUsage(e,t){null==t.taskError&&C(e.runTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime,t.taskPerformance?.runTime??0)}updateWaitTimeWorkerUsage(e,t){const s=k.now(),r=s-(t.timestamp??s);C(e.waitTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime,r)}updateEluWorkerUsage(e,t){if(null!=t.taskError)return;const s=this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu;C(e.elu.active,s,t.taskPerformance?.elu?.active??0),C(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===m.dynamic&&!this.full&&this.internalBusy()}createAndSetupWorkerNode(){const e=this.createWorker();e.on("online",this.opts.onlineHandler??f),e.on("message",this.opts.messageHandler??f),e.on("error",this.opts.errorHandler??f),e.on("error",(t=>{const s=this.getWorkerNodeKeyByWorker(e),r=this.getWorkerInfo(s);r.ready=!1,this.workerNodes[s].closeChannel(),this.emitter?.emit(w.error,t),!0===this.opts.restartWorkerOnError&&!this.starting&&this.started&&(r.dynamic?this.createAndSetupDynamicWorkerNode():this.createAndSetupWorkerNode()),!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(s)})),e.on("exit",this.opts.exitHandler??f),e.once("exit",(()=>{this.removeWorkerNode(e)}));const t=this.addWorkerNode(e);return this.afterWorkerNodeSetup(t),t}createAndSetupDynamicWorkerNode(){const e=this.createAndSetupWorkerNode();this.registerWorkerMessageListener(e,(e=>{const t=this.getWorkerNodeKeyByWorkerId(e.workerId),s=this.workerNodes[t].usage;(b(z.HARD,e.kill)||b(z.SOFT,e.kill)&&(!1===this.opts.enableTasksQueue&&0===s.tasks.executing||!0===this.opts.enableTasksQueue&&0===s.tasks.executing&&0===this.tasksQueueSize(t)))&&this.destroyWorkerNode(t).catch((e=>{this.emitter?.emit(w.error,e)}))}));const t=this.getWorkerInfo(e);return this.sendToWorker(e,{checkActive:!0,workerId:t.id}),t.dynamic=!0,(this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerReady||this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerUsage)&&(t.ready=!0),this.checkAndEmitDynamicWorkerCreationEvents(),e}afterWorkerNodeSetup(e){this.registerWorkerMessageListener(e,this.workerListener()),this.sendStartupMessageToWorker(e),this.sendStatisticsMessageToWorker(e),!0===this.opts.enableTasksQueue&&(this.workerNodes[e].onEmptyQueue=this.taskStealingOnEmptyQueue.bind(this),this.workerNodes[e].onBackPressure=this.tasksStealingOnBackPressure.bind(this))}sendStatisticsMessageToWorker(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate},workerId:this.getWorkerInfo(e).id})}redistributeQueuedTasks(e){for(;this.tasksQueueSize(e)>0;){let t,s=1/0;for(const[r,i]of this.workerNodes.entries())if(i.info.ready&&r!==e){if(0===i.usage.tasks.queued){t=r;break}i.usage.tasks.queued<s&&(s=i.usage.tasks.queued,t=r)}if(null!=t){const s=this.workerNodes[t],r={...this.dequeueTask(e),workerId:s.info.id};0===this.tasksQueueSize(t)&&s.usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency?this.executeTask(t,r):this.enqueueTask(t,r)}}}taskStealingOnEmptyQueue(e){const t=this.getWorkerNodeKeyByWorkerId(e),s=this.workerNodes[t],r=this.workerNodes.slice().sort(((e,t)=>t.usage.tasks.queued-e.usage.tasks.queued));for(const i of r){if(0===i.usage.tasks.queued)break;if(i.info.ready&&i.info.id!==e&&i.usage.tasks.queued>0){const e={...i.popTask(),workerId:s.info.id};if(0===this.tasksQueueSize(t)&&s.usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency?this.executeTask(t,e):this.enqueueTask(t,e),null!=s?.usage&&++s.usage.tasks.stolen,this.shallUpdateTaskFunctionWorkerUsage(t)&&null!=s.getTaskFunctionWorkerUsage(e.name)){++s.getTaskFunctionWorkerUsage(e.name).tasks.stolen}break}}}tasksStealingOnBackPressure(e){if(this.opts.tasksQueueOptions?.size<=1)return;const t=this.workerNodes[this.getWorkerNodeKeyByWorkerId(e)],s=this.workerNodes.slice().sort(((e,t)=>e.usage.tasks.queued-t.usage.tasks.queued));for(const[r,i]of s.entries())if(t.usage.tasks.queued>0&&i.info.ready&&i.info.id!==e&&i.usage.tasks.queued<this.opts.tasksQueueOptions?.size-1){const e={...t.popTask(),workerId:i.info.id};if(0===this.tasksQueueSize(r)&&i.usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency?this.executeTask(r,e):this.enqueueTask(r,e),null!=i?.usage&&++i.usage.tasks.stolen,this.shallUpdateTaskFunctionWorkerUsage(r)&&null!=i.getTaskFunctionWorkerUsage(e.name)){++i.getTaskFunctionWorkerUsage(e.name).tasks.stolen}}}workerListener(){return e=>{this.checkMessageWorkerId(e),null!=e.ready&&null!=e.taskFunctions?this.handleWorkerReadyResponse(e):null!=e.taskId?this.handleTaskExecutionResponse(e):null!=e.taskFunctions&&(this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId)).taskFunctions=e.taskFunctions)}}handleWorkerReadyResponse(e){if(!1===e.ready)throw new Error(`Worker ${e.workerId} failed to initialize`);const t=this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId));t.ready=e.ready,t.taskFunctions=e.taskFunctions,null!=this.emitter&&this.ready&&this.emitter.emit(w.ready,this.info)}handleTaskExecutionResponse(e){const{taskId:t,taskError:s,data:r}=e,i=this.promiseResponseMap.get(t);if(null!=i){null!=s?(this.emitter?.emit(w.taskError,s),i.reject(s.message)):i.resolve(r);const o=i.workerNodeKey;this.afterTaskExecutionHook(o,e),this.promiseResponseMap.delete(t),!0===this.opts.enableTasksQueue&&this.tasksQueueSize(o)>0&&this.workerNodes[o].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&this.executeTask(o,this.dequeueTask(o)),this.workerChoiceStrategyContext.update(o)}}checkAndEmitTaskExecutionEvents(){this.busy&&this.emitter?.emit(w.busy,this.info)}checkAndEmitTaskQueuingEvents(){this.hasBackPressure()&&this.emitter?.emit(w.backPressure,this.info)}checkAndEmitDynamicWorkerCreationEvents(){this.type===m.dynamic&&this.full&&this.emitter?.emit(w.full,this.info)}getWorkerInfo(e){return this.workerNodes[e]?.info}addWorkerNode(e){const t=new H(e,this.worker,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 node added not found");return s}removeWorkerNode(e){const t=this.getWorkerNodeKeyByWorker(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategyContext.remove(t))}hasWorkerNodeBackPressure(e){return!0===this.opts.enableTasksQueue&&this.workerNodes[e].hasBackPressure()}hasBackPressure(){return!0===this.opts.enableTasksQueue&&-1===this.workerNodes.findIndex((e=>!e.hasBackPressure()))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(e,t,t.transferList),this.checkAndEmitTaskExecutionEvents()}enqueueTask(e,t){const s=this.workerNodes[e].enqueueTask(t);return this.checkAndEmitTaskQueuingEvents(),s}dequeueTask(e){return this.workerNodes[e].dequeueTask()}tasksQueueSize(e){return this.workerNodes[e].tasksQueueSize()}flushTasksQueue(e){for(;this.tasksQueueSize(e)>0;)this.executeTask(e,this.dequeueTask(e));this.workerNodes[e].clearTasksQueue()}flushTasksQueues(){for(const[e]of this.workerNodes.entries())this.flushTasksQueue(e)}}class G extends ${opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}setupHook(){a.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return a.isPrimary}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e].worker,s=new Promise((e=>{t.on("exit",(()=>{e()}))}));t.on("disconnect",(()=>{t.kill()})),await this.sendKillMessageToWorker(e,t.id),t.disconnect(),await s}sendToWorker(e,t){this.workerNodes[e].worker.send(t)}sendStartupMessageToWorker(e){this.sendToWorker(e,{ready:!1,workerId:this.workerNodes[e].worker.id})}registerWorkerMessageListener(e,t){this.workerNodes[e].worker.on("message",t)}createWorker(){return a.fork(this.opts.env)}get type(){return m.fixed}get worker(){return j.cluster}get busy(){return this.internalBusy()}}class Y extends G{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return m.dynamic}get busy(){return this.full&&this.internalBusy()}}class J extends ${opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}isMain(){return s}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e],s=t.worker,r=new Promise((e=>{s.on("exit",(()=>{e()}))}));await this.sendKillMessageToWorker(e,s.threadId),t.closeChannel(),await s.terminate(),await r}sendToWorker(e,t,s){this.workerNodes[e].messageChannel.port1.postMessage(t,s)}sendStartupMessageToWorker(e){const t=this.workerNodes[e].worker,s=this.workerNodes[e].messageChannel.port2;t.postMessage({ready:!1,workerId:t.threadId,port:s},[s])}registerWorkerMessageListener(e,t){this.workerNodes[e].messageChannel.port1.on("message",t)}createWorker(){return new r(this.filePath,{env:i,...this.opts.workerOptions})}get type(){return m.fixed}get worker(){return j.thread}get busy(){return this.internalBusy()}}class X extends J{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return m.dynamic}get busy(){return this.full&&this.internalBusy()}}const Z=6e4,ee={killBehavior:z.SOFT,maxInactiveTime:Z,killHandler:f};class te extends g{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,s,r,i=ee){if(super(e),this.isMain=t,this.mainWorker=s,this.opts=i,null==this.isMain)throw new Error("isMain parameter is mandatory");this.checkTaskFunctions(r),this.checkWorkerOptions(this.opts),this.isMain||this.getMainWorker().on("message",this.handleReadyMessage.bind(this))}checkWorkerOptions(e){this.opts={...ee,...e},delete this.opts.async}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(y,t),this.taskFunctions.set("string"==typeof e.name&&e.name.trim().length>0?e.name:"fn1",t)}else{if(!v(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)){if("string"!=typeof s)throw new TypeError("A taskFunctions parameter object key is not a string");if("string"==typeof s&&0===s.trim().length)throw new TypeError("A taskFunctions parameter object key is an empty string");if("function"!=typeof r)throw new TypeError("A taskFunctions parameter object value is not a function");const e=r.bind(this);t&&(this.taskFunctions.set(y,e),t=!1),this.taskFunctions.set(s,e)}if(t)throw new Error("taskFunctions parameter object is empty")}}}hasTaskFunction(e){return this.checkTaskFunctionName(e),this.taskFunctions.has(e)}addTaskFunction(e,t){if(this.checkTaskFunctionName(e),e===y)throw new Error("Cannot add a task function with the default reserved name");if("function"!=typeof t)throw new TypeError("fn parameter is not a function");try{const s=t.bind(this);return this.taskFunctions.get(e)===this.taskFunctions.get(y)&&this.taskFunctions.set(y,s),this.taskFunctions.set(e,s),this.sendTaskFunctionsListToMainWorker(),!0}catch{return!1}}removeTaskFunction(e){if(this.checkTaskFunctionName(e),e===y)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(y))throw new Error("Cannot remove the task function used as the default task function");const t=this.taskFunctions.delete(e);return this.sendTaskFunctionsListToMainWorker(),t}listTaskFunctions(){const e=[...this.taskFunctions.keys()];let t=y;for(const[e,s]of this.taskFunctions)if(e!==y&&s===this.taskFunctions.get(y)){t=e;break}return[e[e.indexOf(y)],t,...e.filter((e=>e!==y&&e!==t))]}setDefaultTaskFunction(e){if(this.checkTaskFunctionName(e),e===y)throw new Error("Cannot set the default task function reserved name as the default task function");if(!this.taskFunctions.has(e))throw new Error("Cannot set the default task function to a non-existing task function");try{return this.taskFunctions.set(y,this.taskFunctions.get(e)),!0}catch{return!1}}checkTaskFunctionName(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("name parameter is an empty string")}messageListener(e){this.checkMessageWorkerId(e),null!=e.statistics?this.statistics=e.statistics:null!=e.checkActive?e.checkActive?this.startCheckActive():this.stopCheckActive():null!=e.taskId&&null!=e.data?this.run(e):!0===e.kill&&this.handleKillMessage(e)}handleKillMessage(e){if(this.stopCheckActive(),I(this.opts.killHandler))(this.opts.killHandler?.()).then((()=>(this.sendToMainWorker({kill:"success",workerId:this.id}),null))).catch((()=>{this.sendToMainWorker({kill:"failure",workerId:this.id})})).finally((()=>{this.emitDestroy()})).catch(f);else try{this.opts.killHandler?.(),this.sendToMainWorker({kill:"success",workerId:this.id})}catch{this.sendToMainWorker({kill:"failure",workerId:this.id})}finally{this.emitDestroy()}}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Message worker id is not set");if(null!=e.workerId&&e.workerId!==this.id)throw new Error(`Message worker id ${e.workerId} does not match the worker id ${this.id}`)}startCheckActive(){this.lastTaskTimestamp=k.now(),this.activeInterval=setInterval(this.checkActive.bind(this),(this.opts.maxInactiveTime??Z)/2)}stopCheckActive(){null!=this.activeInterval&&(clearInterval(this.activeInterval),delete this.activeInterval)}checkActive(){k.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??Z)&&this.sendToMainWorker({kill:this.opts.killBehavior,workerId:this.id})}getMainWorker(){if(null==this.mainWorker)throw new Error("Main worker not set");return this.mainWorker}sendTaskFunctionsListToMainWorker(){this.sendToMainWorker({taskFunctions:this.listTaskFunctions(),workerId:this.id})}handleError(e){return e instanceof Error?e.message:e}run(e){const{name:t,taskId:s,data:r}=e,i=this.taskFunctions.get(t??y);null!=i?I(i)?this.runInAsyncScope(this.runAsync.bind(this),this,i,e):this.runInAsyncScope(this.runSync.bind(this),this,i,e):this.sendToMainWorker({taskError:{name:t,message:`Task function '${t}' not found`,data:r},workerId:this.id,taskId:s})}runSync(e,t){const{name:s,taskId:r,data:i}=t;try{let t=this.beginTaskPerformance(s);const o=e(i);t=this.endTaskPerformance(t),this.sendToMainWorker({data:o,taskPerformance:t,workerId:this.id,taskId:r})}catch(e){const t=this.handleError(e);this.sendToMainWorker({taskError:{name:s,message:t,data:i},workerId:this.id,taskId:r})}finally{this.updateLastTaskTimestamp()}}runAsync(e,t){const{name:s,taskId:r,data:i}=t;let o=this.beginTaskPerformance(s);e(i).then((e=>(o=this.endTaskPerformance(o),this.sendToMainWorker({data:e,taskPerformance:o,workerId:this.id,taskId:r}),null))).catch((e=>{const t=this.handleError(e);this.sendToMainWorker({taskError:{name:s,message:t,data:i},workerId:this.id,taskId:r})})).finally((()=>{this.updateLastTaskTimestamp()})).catch(f)}beginTaskPerformance(e){return this.checkStatistics(),{name:e??y,timestamp:k.now(),...this.statistics.elu&&{elu:k.eventLoopUtilization()}}}endTaskPerformance(e){return this.checkStatistics(),{...e,...this.statistics.runTime&&{runTime:k.now()-e.timestamp},...this.statistics.elu&&{elu:k.eventLoopUtilization(e.elu)}}}checkStatistics(){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set")}updateLastTaskTimestamp(){null!=this.activeInterval&&(this.lastTaskTimestamp=k.now())}}class se extends te{constructor(e,t={}){super("worker-cluster-pool:poolifier",a.isPrimary,a.worker,e,t)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready)try{this.getMainWorker().on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctions:this.listTaskFunctions(),workerId:this.id})}catch{this.sendToMainWorker({ready:!1,taskFunctions:this.listTaskFunctions(),workerId:this.id})}}get id(){return this.getMainWorker().id}sendToMainWorker(e){this.getMainWorker().send(e)}}class re extends te{port;constructor(e,t={}){super("worker-thread-pool:poolifier",s,o,e,t)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready&&null!=e.port)try{this.port=e.port,this.port.on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctions:this.listTaskFunctions(),workerId:this.id})}catch{this.sendToMainWorker({ready:!1,taskFunctions:this.listTaskFunctions(),workerId:this.id})}}handleKillMessage(e){super.handleKillMessage(e),this.port?.unref(),this.port?.close()}get id(){return n}sendToMainWorker(e){this.port.postMessage(e)}handleError(e){return e}}export{se as ClusterWorker,Y as DynamicClusterPool,X as DynamicThreadPool,G as FixedClusterPool,J as FixedThreadPool,z as KillBehaviors,Q as Measurements,w as PoolEvents,m as PoolTypes,re as ThreadWorker,O as WorkerChoiceStrategies,j as WorkerTypes,N as availableParallelism};
1
+ import{EventEmitter as e}from"node:events";import{Worker as t,MessageChannel as s,isMainThread as r,SHARE_ENV as i,parentPort as o,threadId as n}from"node:worker_threads";import a,{Worker as h}from"node:cluster";import{webcrypto as u,randomUUID as k}from"node:crypto";import{performance as c}from"node:perf_hooks";import{existsSync as d}from"node:fs";import*as l from"node:os";import{cpus as g}from"node:os";import{AsyncResource as m}from"node:async_hooks";const p=Object.freeze({fixed:"fixed",dynamic:"dynamic"});class w extends e{}const y=Object.freeze({ready:"ready",busy:"busy",full:"full",destroy:"destroy",error:"error",taskError:"taskError",backPressure:"backPressure"}),f=Object.freeze({thread:"thread",cluster:"cluster"}),T="default",W=Object.freeze((()=>{})),N={retries:6,runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},x={aggregate:!1,average:!1,median:!1},S=()=>{let e=1;try{e=l.availableParallelism()}catch{const t=l.cpus();Array.isArray(t)&&t.length>0&&(e=t.length)}return e},E=e=>e instanceof t?f.thread:e instanceof h?f.cluster:void 0,v=e=>e instanceof t?e.threadId:e instanceof h?e.id:void 0,b=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,I=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},C=(e,t=2)=>{const s=Math.pow(10,t);return Math.round(e*s*(1+Number.EPSILON))/s},z=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),R=(e,t)=>t===e,O=e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name,Q=(e,t,s)=>{t.aggregate&&(e.aggregate=(e.aggregate??0)+s,e.minimum=Math.min(s,e.minimum??1/0),e.maximum=Math.max(s,e.maximum??-1/0),(t.average||t.median)&&null!=s&&(e.history.push(s),t.average?e.average=b(e.history):null!=e.average&&delete e.average,t.median?e.median=I(e.history):null!=e.median&&delete e.median))},F=()=>u.getRandomValues(new Uint32Array(1))[0]/4294967296,M=Object.freeze({SOFT:"SOFT",HARD:"HARD"}),K=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"}),q=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"});class P{pool;opts;nextWorkerNodeKey=0;previousWorkerNodeKey=0;strategyPolicy={dynamicWorkerUsage:!1,dynamicWorkerReady:!0};taskStatisticsRequirements={runTime:x,waitTime:x,elu:x};constructor(e,t=N){this.pool=e,this.opts=t,this.opts={...N,...t},this.choose=this.choose.bind(this)}setTaskStatisticsRequirements(e){this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.runTime,e.runTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.waitTime,e.waitTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.elu,e.elu?.median)}toggleMedianMeasurementStatisticsRequirements(e,t){e.average&&t&&(e.average=!1,e.median=t),e.median&&!t&&(e.average=!0,e.median=t)}resetWorkerNodeKeyProperties(){this.nextWorkerNodeKey=0,this.previousWorkerNodeKey=0}setOptions(e){this.opts={...N,...e},this.setTaskStatisticsRequirements(this.opts)}isWorkerNodeReady(e){return this.pool.workerNodes[e].info.ready}hasWorkerNodeBackPressure(e){return this.pool.hasWorkerNodeBackPressure(e)}isWorkerNodeEligible(e){return this.isWorkerNodeReady(e)&&!this.hasWorkerNodeBackPressure(e)}getWorkerTaskRunTime(e){return this.taskStatisticsRequirements.runTime.median?this.pool.workerNodes[e].usage.runTime?.median??0:this.pool.workerNodes[e].usage.runTime?.average??0}getWorkerTaskWaitTime(e){return this.taskStatisticsRequirements.waitTime.median?this.pool.workerNodes[e].usage.waitTime?.median??0:this.pool.workerNodes[e].usage.waitTime?.average??0}getWorkerTaskElu(e){return this.taskStatisticsRequirements.elu.median?this.pool.workerNodes[e].usage.elu.active?.median??0:this.pool.workerNodes[e].usage.elu.active?.average??0}checkNextWorkerNodeEligibility(e){this.isWorkerNodeEligible(this.nextWorkerNodeKey)||(this.nextWorkerNodeKey=void 0,this.previousWorkerNodeKey=e??this.previousWorkerNodeKey)}computeDefaultWorkerWeight(){let e=0;for(const t of g()){const s=t.speed.toString().length-1;e+=1/(t.speed/Math.pow(10,s))*Math.pow(10,s)}return Math.round(e/g().length)}}class A extends P{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:x,elu:{aggregate:!0,average:!0,median:!1}};workersVirtualTaskEndTimestamp=[];constructor(e,t=N){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.workersVirtualTaskEndTimestamp=[],!0}update(e){return this.computeWorkerVirtualTaskEndTimestamp(e),!0}choose(){return this.nextWorkerNodeKey=this.fairShareNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(e){return this.workersVirtualTaskEndTimestamp.splice(e,1),!0}fairShareNextWorkerNodeKey(){let e,t=1/0;for(const[s]of this.pool.workerNodes.entries()){if(!this.isWorkerNodeEligible(s))continue;null==this.workersVirtualTaskEndTimestamp[s]&&this.computeWorkerVirtualTaskEndTimestamp(s);const r=this.workersVirtualTaskEndTimestamp[s];r<t&&(t=r,e=s)}return e}computeWorkerVirtualTaskEndTimestamp(e){this.workersVirtualTaskEndTimestamp[e]=this.getWorkerVirtualTaskEndTimestamp(e,this.getWorkerVirtualTaskStartTimestamp(e))}getWorkerVirtualTaskEndTimestamp(e,t){return t+(this.opts.measurement===q.elu?this.getWorkerTaskElu(e):this.getWorkerTaskRunTime(e))}getWorkerVirtualTaskStartTimestamp(e){return Math.max(performance.now(),this.workersVirtualTaskEndTimestamp[e]??-1/0)}}class U extends P{roundId=0;roundWeights;defaultWorkerWeight;constructor(e,t=N){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight(),this.roundWeights=this.getRoundWeights()}reset(){return this.resetWorkerNodeKeyProperties(),this.roundId=0,!0}update(){return!0}choose(){let e,t;for(let s=this.roundId;s<this.roundWeights.length;s++){e=s;for(let e=this.nextWorkerNodeKey??this.previousWorkerNodeKey;e<this.pool.workerNodes.length;e++){if(!this.isWorkerNodeEligible(e))continue;if((this.opts.weights?.[e]??this.defaultWorkerWeight)>=this.roundWeights[s]){t=e;break}}}this.roundId=e,null==t&&(this.previousWorkerNodeKey=this.nextWorkerNodeKey??this.previousWorkerNodeKey),this.nextWorkerNodeKey=t;const s=this.nextWorkerNodeKey;return this.nextWorkerNodeKey===this.pool.workerNodes.length-1?(this.nextWorkerNodeKey=0,this.roundId=this.roundId===this.roundWeights.length-1?0:this.roundId+1):this.nextWorkerNodeKey=(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,s}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1,this.roundId=this.roundId===this.roundWeights.length-1?0:this.roundId+1)),!0}setOptions(e){super.setOptions(e),this.roundWeights=this.getRoundWeights()}getRoundWeights(){return null==this.opts.weights?[this.defaultWorkerWeight]:[...new Set(Object.values(this.opts.weights).slice().sort(((e,t)=>e-t)))]}}class B extends P{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:x};constructor(e,t=N){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.nextWorkerNodeKey=this.leastBusyNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastBusyNextWorkerNodeKey(){let e,t=1/0;for(const[s,r]of this.pool.workerNodes.entries()){if(!this.isWorkerNodeEligible(s))continue;const i=(r.usage.runTime?.aggregate??0)+(r.usage.waitTime?.aggregate??0);if(0===i){e=s;break}i<t&&(t=i,e=s)}return e}}class D extends P{constructor(e,t=N){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.nextWorkerNodeKey=this.leastUsedNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastUsedNextWorkerNodeKey(){let e,t=1/0;for(const[s,r]of this.pool.workerNodes.entries()){if(!this.isWorkerNodeEligible(s))continue;const i=r.usage.tasks,o=i.executed+i.executing+i.queued;if(0===o){e=s;break}o<t&&(t=o,e=s)}return e}}class L extends P{taskStatisticsRequirements={runTime:x,waitTime:x,elu:{aggregate:!0,average:!1,median:!1}};constructor(e,t=N){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.nextWorkerNodeKey=this.leastEluNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastEluNextWorkerNodeKey(){let e,t=1/0;for(const[s,r]of this.pool.workerNodes.entries()){if(!this.isWorkerNodeEligible(s))continue;const i=r.usage,o=i.elu?.active?.aggregate??0;if(0===o){e=s;break}o<t&&(t=o,e=s)}return e}}class V extends P{constructor(e,t=N){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.resetWorkerNodeKeyProperties(),!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;return this.roundRobinNextWorkerNodeKey(),this.checkNextWorkerNodeEligibility(e),e}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=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 _ extends P{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:x,elu:x};defaultWorkerWeight;workerVirtualTaskRunTime=0;constructor(e,t=N){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight()}reset(){return this.resetWorkerNodeKeyProperties(),this.workerVirtualTaskRunTime=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;return this.weightedRoundRobinNextWorkerNodeKey(),this.checkNextWorkerNodeEligibility(e),e}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1),this.workerVirtualTaskRunTime=0),!0}weightedRoundRobinNextWorkerNodeKey(){const e=this.workerVirtualTaskRunTime;return e<(this.opts.weights?.[this.nextWorkerNodeKey??this.previousWorkerNodeKey]??this.defaultWorkerWeight)?this.workerVirtualTaskRunTime=e+this.getWorkerTaskRunTime(this.nextWorkerNodeKey??this.previousWorkerNodeKey):(this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,this.workerVirtualTaskRunTime=0),this.nextWorkerNodeKey}}class j{workerChoiceStrategy;opts;workerChoiceStrategies;retriesCount=0;constructor(e,t=K.ROUND_ROBIN,s=N){this.workerChoiceStrategy=t,this.opts=s,this.opts={...N,...s},this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[K.ROUND_ROBIN,new(V.bind(this))(e,s)],[K.LEAST_USED,new(D.bind(this))(e,s)],[K.LEAST_BUSY,new(B.bind(this))(e,s)],[K.LEAST_ELU,new(L.bind(this))(e,s)],[K.FAIR_SHARE,new(A.bind(this))(e,s)],[K.WEIGHTED_ROUND_ROBIN,new(_.bind(this))(e,s)],[K.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).choose();if(null==e&&this.retriesCount<this.opts.retries)return this.retriesCount++,this.execute();if(null==e)throw new Error(`Worker node key chosen is null or undefined after ${this.retriesCount} retries`);return this.retriesCount=0,e}remove(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).remove(e)}setOptions(e){this.opts={...N,...e};for(const t of this.workerChoiceStrategies.values())t.setOptions(e)}}class H 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 H(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 G{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?this.head=void 0:this.tail.next=void 0,--this.size,e?.data}shift(){if(null==this.head)return;const e=this.head;return this.head=this.head.next,null==this.head?this.tail=void 0:this.head.prev=void 0,--this.size,e?.data}peekFirst(){return this.head?.data}peekLast(){return this.tail?.data}clear(){this.head=void 0,this.tail=void 0,this.size=0,this.maxSize=0}[Symbol.iterator](){let e=this.head;return{next:()=>{if(null==e)return{value:void 0,done:!0};const t={value:e.data,done:!1};return e=e.next,t}}}backward(){return{[Symbol.iterator]:()=>{let e=this.tail;return{next:()=>{if(null==e)return{value:void 0,done:!0};const t={value:e.data,done:!1};return e=e.prev,t}}}}}incrementSize(){return++this.size,this.size>this.maxSize&&(this.maxSize=this.size),this.size}}class Y{worker;info;usage;messageChannel;tasksQueueBackPressureSize;onBackPressure;onEmptyQueue;tasksQueue;onEmptyQueueCount;taskFunctionsUsage;constructor(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");this.worker=e,this.info=this.initWorkerInfo(e),this.usage=this.initWorkerUsage(),this.info.type===f.thread&&(this.messageChannel=new s),this.tasksQueueBackPressureSize=t,this.tasksQueue=new G,this.onEmptyQueueCount=0,this.taskFunctionsUsage=new Map}tasksQueueSize(){return this.tasksQueue.size}enqueueTask(e){const t=this.tasksQueue.push(e);return null!=this.onBackPressure&&this.hasBackPressure()&&this.onBackPressure(this.info.id),t}unshiftTask(e){const t=this.tasksQueue.unshift(e);return null!=this.onBackPressure&&this.hasBackPressure()&&this.onBackPressure(this.info.id),t}dequeueTask(){const e=this.tasksQueue.shift();return null!=this.onEmptyQueue&&0===this.tasksQueue.size&&this.startOnEmptyQueue().catch(W),e}popTask(){const e=this.tasksQueue.pop();return null!=this.onEmptyQueue&&0===this.tasksQueue.size&&this.startOnEmptyQueue().catch(W),e}clearTasksQueue(){this.tasksQueue.clear()}hasBackPressure(){return this.tasksQueue.size>=this.tasksQueueBackPressureSize}resetUsage(){this.usage=this.initWorkerUsage(),this.taskFunctionsUsage.clear()}closeChannel(){null!=this.messageChannel&&(this.messageChannel?.port1.unref(),this.messageChannel?.port2.unref(),this.messageChannel?.port1.close(),this.messageChannel?.port2.close(),delete this.messageChannel)}getTaskFunctionWorkerUsage(e){if(!Array.isArray(this.info.taskFunctions))throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function names list is not yet defined`);if(Array.isArray(this.info.taskFunctions)&&this.info.taskFunctions.length<3)throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function names list has less than 3 elements`);return e===T&&(e=this.info.taskFunctions[1]),this.taskFunctionsUsage.has(e)||this.taskFunctionsUsage.set(e,this.initTaskFunctionWorkerUsage(e)),this.taskFunctionsUsage.get(e)}async startOnEmptyQueue(){this.onEmptyQueueCount>0&&(this.usage.tasks.executing>0||this.tasksQueue.size>0)?this.onEmptyQueueCount=0:(this.onEmptyQueue(this.info.id),++this.onEmptyQueueCount,await(async e=>{await new Promise((t=>{setTimeout(t,e)}))})(((e=0,t=100)=>{const s=Math.pow(2,e)*t;return s+.2*s*F()})(this.onEmptyQueueCount)),await this.startOnEmptyQueue())}initWorkerInfo(e){return{id:v(e),type:E(e),dynamic:!1,ready:!1}}initWorkerUsage(){const e=()=>this.tasksQueue.size,t=()=>this.tasksQueue.maxSize;return{tasks:{executed:0,executing:0,get queued(){return e()},get maxQueued(){return t()},stolen:0,failed:0},runTime:{history:new H},waitTime:{history:new H},elu:{idle:{history:new H},active:{history:new H}}}}initTaskFunctionWorkerUsage(e){const t=()=>{let t=0;for(const s of this.tasksQueue)(s.name===T&&e===this.info.taskFunctions[1]||s.name!==T&&e===s.name)&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},stolen:0,failed:0},runTime:{history:new H},waitTime:{history:new H},elu:{idle:{history:new H},active:{history:new H}}}}}class J{numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;max;starting;started;startTimestamp;constructor(e,t,s){if(this.numberOfWorkers=e,this.filePath=t,this.opts=s,!this.isMain())throw new Error("Cannot start a pool from a worker with the same type as the pool");this.checkNumberOfWorkers(this.numberOfWorkers),this.checkFilePath(this.filePath),this.checkPoolOptions(this.opts),this.chooseWorkerNode=this.chooseWorkerNode.bind(this),this.executeTask=this.executeTask.bind(this),this.enqueueTask=this.enqueueTask.bind(this),!0===this.opts.enableEvents&&(this.emitter=new w),this.workerChoiceStrategyContext=new j(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook(),this.starting=!0,this.startPool(),this.starting=!1,this.started=!0,this.startTimestamp=c.now()}checkFilePath(e){if(null==e||"string"!=typeof e||"string"==typeof e&&0===e.trim().length)throw new Error("Please specify a file with a worker implementation");if(!d(e))throw new Error(`Cannot find the worker file '${e}'`)}checkNumberOfWorkers(e){if(null==e)throw new Error("Cannot instantiate a pool without specifying the number of workers");if(!Number.isSafeInteger(e))throw new TypeError("Cannot instantiate a pool with a non safe integer number of workers");if(e<0)throw new RangeError("Cannot instantiate a pool with a negative number of workers");if(this.type===p.fixed&&0===e)throw new RangeError("Cannot instantiate a fixed pool with zero worker")}checkDynamicPoolSize(e,t){if(this.type===p.dynamic){if(null==t)throw new TypeError("Cannot instantiate a dynamic pool without specifying the maximum pool size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot instantiate a dynamic pool with a non safe integer maximum pool size");if(e>t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size");if(0===t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size equal to zero");if(e===t)throw new RangeError("Cannot instantiate a dynamic pool with a minimum pool size equal to the maximum pool size. Use a fixed pool instead")}}checkPoolOptions(e){if(!z(e))throw new TypeError("Invalid pool options: must be a plain object");this.opts.workerChoiceStrategy=e.workerChoiceStrategy??K.ROUND_ROBIN,this.checkValidWorkerChoiceStrategy(this.opts.workerChoiceStrategy),this.opts.workerChoiceStrategyOptions={...N,...e.workerChoiceStrategyOptions},this.checkValidWorkerChoiceStrategyOptions(this.opts.workerChoiceStrategyOptions),this.opts.restartWorkerOnError=e.restartWorkerOnError??!0,this.opts.enableEvents=e.enableEvents??!0,this.opts.enableTasksQueue=e.enableTasksQueue??!1,this.opts.enableTasksQueue&&(this.checkValidTasksQueueOptions(e.tasksQueueOptions),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e.tasksQueueOptions))}checkValidWorkerChoiceStrategy(e){if(!Object.values(K).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)}checkValidWorkerChoiceStrategyOptions(e){if(!z(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(q).includes(e.measurement))throw new Error(`Invalid worker choice strategy options: invalid measurement '${e.measurement}'`)}checkValidTasksQueueOptions(e){if(null!=e&&!z(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?.queueMaxSize)throw new Error("Invalid tasks queue options: queueMaxSize is deprecated, please use size instead");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`)}startPool(){for(;this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.numberOfWorkers;)this.createAndSetupWorkerNode()}get info(){return{version:"2.6.37",type:this.type,worker:this.worker,ready:this.ready,strategy:this.opts.workerChoiceStrategy,minSize:this.minSize,maxSize:this.maxSize,...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{utilization:C(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:C(Math.min(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:C(Math.max(...this.workerNodes.map((e=>e.usage.runTime?.maximum??-1/0)))),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.average&&{average:C(b(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&{median:C(I(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:C(Math.min(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:C(Math.max(...this.workerNodes.map((e=>e.usage.waitTime?.maximum??-1/0)))),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.average&&{average:C(b(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.waitTime.history)),[])))},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&{median:C(I(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=(c.now()-this.startTimestamp)*this.maxSize;return(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)+this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0))/e}get minSize(){return this.numberOfWorkers}get maxSize(){return this.max??this.numberOfWorkers}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Worker message received without worker id");if(null!=e.workerId&&-1===this.getWorkerNodeKeyByWorkerId(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKeyByWorker(e){return this.workerNodes.findIndex((t=>t.worker===e))}getWorkerNodeKeyByWorkerId(e){return this.workerNodes.findIndex((t=>t.info.id===e))}setWorkerChoiceStrategy(e,t){this.checkValidWorkerChoiceStrategy(e),this.opts.workerChoiceStrategy=e,this.workerChoiceStrategyContext.setWorkerChoiceStrategy(this.opts.workerChoiceStrategy),null!=t&&this.setWorkerChoiceStrategyOptions(t);for(const[e,t]of this.workerNodes.entries())t.resetUsage(),this.sendStatisticsMessageToWorker(e)}setWorkerChoiceStrategyOptions(e){this.checkValidWorkerChoiceStrategyOptions(e),this.opts.workerChoiceStrategyOptions={...N,...e},this.workerChoiceStrategyContext.setOptions(this.opts.workerChoiceStrategyOptions)}enableTasksQueue(e,t){!0!==this.opts.enableTasksQueue||e||this.flushTasksQueues(),this.opts.enableTasksQueue=e,this.setTasksQueueOptions(t)}setTasksQueueOptions(e){!0===this.opts.enableTasksQueue?(this.checkValidTasksQueueOptions(e),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e),this.setTasksQueueMaxSize(this.opts.tasksQueueOptions.size)):null!=this.opts.tasksQueueOptions&&delete this.opts.tasksQueueOptions}setTasksQueueMaxSize(e){for(const t of this.workerNodes)t.tasksQueueBackPressureSize=e}buildTasksQueueOptions(e){return{size:Math.pow(this.maxSize,2),concurrency:1,...e}}get full(){return this.workerNodes.length>=this.maxSize}internalBusy(){return!0===this.opts.enableTasksQueue?-1===this.workerNodes.findIndex((e=>e.info.ready&&e.usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency)):-1===this.workerNodes.findIndex((e=>e.info.ready&&0===e.usage.tasks.executing))}listTaskFunctions(){for(const e of this.workerNodes)if(Array.isArray(e.info.taskFunctions)&&e.info.taskFunctions.length>0)return e.info.taskFunctions;return[]}shallExecuteTask(e){return 0===this.tasksQueueSize(e)&&this.workerNodes[e].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency}async execute(e,t,s){return await new Promise(((r,i)=>{if(!this.started)return void i(new Error("Cannot execute a task on destroyed pool"));if(null!=t&&"string"!=typeof t)return void i(new TypeError("name argument must be a string"));if(null!=t&&"string"==typeof t&&0===t.trim().length)return void i(new TypeError("name argument must not be an empty string"));if(null!=s&&!Array.isArray(s))return void i(new TypeError("transferList argument must be an array"));const o=c.now(),n=this.chooseWorkerNode(),a=this.getWorkerInfo(n),h={name:t??T,data:e??{},transferList:s,timestamp:o,workerId:a.id,taskId:k()};this.promiseResponseMap.set(h.taskId,{resolve:r,reject:i,workerNodeKey:n}),!1===this.opts.enableTasksQueue||!0===this.opts.enableTasksQueue&&this.shallExecuteTask(n)?this.executeTask(n,h):this.enqueueTask(n,h)}))}async destroy(){await Promise.all(this.workerNodes.map((async(e,t)=>{await this.destroyWorkerNode(t)}))),this.emitter?.emit(y.destroy,this.info),this.started=!1}async sendKillMessageToWorker(e,t){await new Promise(((s,r)=>{this.registerWorkerMessageListener(e,(e=>{"success"===e.kill?s():"failure"===e.kill&&r(new Error(`Worker ${t} kill message handling failed`))})),this.sendToWorker(e,{kill:!0,workerId:t})}))}setupHook(){}beforeTaskExecutionHook(e,t){if(null!=this.workerNodes[e]?.usage){const s=this.workerNodes[e].usage;++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t)}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name)){const s=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name);++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t)}}afterTaskExecutionHook(e,t){if(null!=this.workerNodes[e]?.usage){const s=this.workerNodes[e].usage;this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t)}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance?.name)){const s=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance?.name);this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t)}}shallUpdateTaskFunctionWorkerUsage(e){const t=this.getWorkerInfo(e);return null!=t&&Array.isArray(t.taskFunctions)&&t.taskFunctions.length>2}updateTaskStatisticsWorkerUsage(e,t){const s=e.tasks;null!=s.executing&&s.executing>0&&--s.executing,null==t.taskError?++s.executed:++s.failed}updateRunTimeWorkerUsage(e,t){null==t.taskError&&Q(e.runTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime,t.taskPerformance?.runTime??0)}updateWaitTimeWorkerUsage(e,t){const s=c.now(),r=s-(t.timestamp??s);Q(e.waitTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime,r)}updateEluWorkerUsage(e,t){if(null!=t.taskError)return;const s=this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu;Q(e.elu.active,s,t.taskPerformance?.elu?.active??0),Q(e.elu.idle,s,t.taskPerformance?.elu?.idle??0),s.aggregate&&null!=t.taskPerformance?.elu&&(null!=e.elu.utilization?e.elu.utilization=(e.elu.utilization+t.taskPerformance.elu.utilization)/2:e.elu.utilization=t.taskPerformance.elu.utilization)}chooseWorkerNode(){if(this.shallCreateDynamicWorker()){const e=this.createAndSetupDynamicWorkerNode();if(this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerUsage)return e}return this.workerChoiceStrategyContext.execute()}shallCreateDynamicWorker(){return this.type===p.dynamic&&!this.full&&this.internalBusy()}createAndSetupWorkerNode(){const e=this.createWorker();e.on("online",this.opts.onlineHandler??W),e.on("message",this.opts.messageHandler??W),e.on("error",this.opts.errorHandler??W),e.on("error",(t=>{const s=this.getWorkerNodeKeyByWorker(e),r=this.getWorkerInfo(s);r.ready=!1,this.workerNodes[s].closeChannel(),this.emitter?.emit(y.error,t),!0===this.opts.restartWorkerOnError&&!this.starting&&this.started&&(r.dynamic?this.createAndSetupDynamicWorkerNode():this.createAndSetupWorkerNode()),!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(s)})),e.on("exit",this.opts.exitHandler??W),e.once("exit",(()=>{this.removeWorkerNode(e)}));const t=this.addWorkerNode(e);return this.afterWorkerNodeSetup(t),t}createAndSetupDynamicWorkerNode(){const e=this.createAndSetupWorkerNode();this.registerWorkerMessageListener(e,(e=>{const t=this.getWorkerNodeKeyByWorkerId(e.workerId),s=this.workerNodes[t].usage;(R(M.HARD,e.kill)||R(M.SOFT,e.kill)&&(!1===this.opts.enableTasksQueue&&0===s.tasks.executing||!0===this.opts.enableTasksQueue&&0===s.tasks.executing&&0===this.tasksQueueSize(t)))&&this.destroyWorkerNode(t).catch((e=>{this.emitter?.emit(y.error,e)}))}));const t=this.getWorkerInfo(e);return this.sendToWorker(e,{checkActive:!0,workerId:t.id}),t.dynamic=!0,(this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerReady||this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerUsage)&&(t.ready=!0),this.checkAndEmitDynamicWorkerCreationEvents(),e}afterWorkerNodeSetup(e){this.registerWorkerMessageListener(e,this.workerListener()),this.sendStartupMessageToWorker(e),this.sendStatisticsMessageToWorker(e),!0===this.opts.enableTasksQueue&&(this.workerNodes[e].onEmptyQueue=this.taskStealingOnEmptyQueue.bind(this),this.workerNodes[e].onBackPressure=this.tasksStealingOnBackPressure.bind(this))}sendStatisticsMessageToWorker(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate},workerId:this.getWorkerInfo(e).id})}redistributeQueuedTasks(e){for(;this.tasksQueueSize(e)>0;){let t,s=1/0;for(const[r,i]of this.workerNodes.entries())if(i.info.ready&&r!==e){if(0===i.usage.tasks.queued){t=r;break}i.usage.tasks.queued<s&&(s=i.usage.tasks.queued,t=r)}if(null!=t){const s=this.workerNodes[t],r={...this.dequeueTask(e),workerId:s.info.id};this.shallExecuteTask(t)?this.executeTask(t,r):this.enqueueTask(t,r)}}}updateTaskStolenStatisticsWorkerUsage(e,t){const s=this.workerNodes[e];if(null!=s?.usage&&++s.usage.tasks.stolen,this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=s.getTaskFunctionWorkerUsage(t)){++s.getTaskFunctionWorkerUsage(t).tasks.stolen}}taskStealingOnEmptyQueue(e){const t=this.getWorkerNodeKeyByWorkerId(e),s=this.workerNodes[t],r=this.workerNodes.slice().sort(((e,t)=>t.usage.tasks.queued-e.usage.tasks.queued));for(const i of r){if(0===i.usage.tasks.queued)break;if(i.info.ready&&i.info.id!==e&&i.usage.tasks.queued>0){const e={...i.popTask(),workerId:s.info.id};this.shallExecuteTask(t)?this.executeTask(t,e):this.enqueueTask(t,e),this.updateTaskStolenStatisticsWorkerUsage(t,e.name);break}}}tasksStealingOnBackPressure(e){if(this.opts.tasksQueueOptions?.size<=1)return;const t=this.workerNodes[this.getWorkerNodeKeyByWorkerId(e)],s=this.workerNodes.slice().sort(((e,t)=>e.usage.tasks.queued-t.usage.tasks.queued));for(const[r,i]of s.entries())if(t.usage.tasks.queued>0&&i.info.ready&&i.info.id!==e&&i.usage.tasks.queued<this.opts.tasksQueueOptions?.size-1){const e={...t.popTask(),workerId:i.info.id};this.shallExecuteTask(r)?this.executeTask(r,e):this.enqueueTask(r,e),this.updateTaskStolenStatisticsWorkerUsage(r,e.name)}}workerListener(){return e=>{this.checkMessageWorkerId(e),null!=e.ready&&null!=e.taskFunctions?this.handleWorkerReadyResponse(e):null!=e.taskId?this.handleTaskExecutionResponse(e):null!=e.taskFunctions&&(this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId)).taskFunctions=e.taskFunctions)}}handleWorkerReadyResponse(e){if(!1===e.ready)throw new Error(`Worker ${e.workerId} failed to initialize`);const t=this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId));t.ready=e.ready,t.taskFunctions=e.taskFunctions,null!=this.emitter&&this.ready&&this.emitter.emit(y.ready,this.info)}handleTaskExecutionResponse(e){const{taskId:t,taskError:s,data:r}=e,i=this.promiseResponseMap.get(t);if(null!=i){null!=s?(this.emitter?.emit(y.taskError,s),i.reject(s.message)):i.resolve(r);const o=i.workerNodeKey;this.afterTaskExecutionHook(o,e),this.promiseResponseMap.delete(t),!0===this.opts.enableTasksQueue&&this.tasksQueueSize(o)>0&&this.workerNodes[o].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&this.executeTask(o,this.dequeueTask(o)),this.workerChoiceStrategyContext.update(o)}}checkAndEmitTaskExecutionEvents(){this.busy&&this.emitter?.emit(y.busy,this.info)}checkAndEmitTaskQueuingEvents(){this.hasBackPressure()&&this.emitter?.emit(y.backPressure,this.info)}checkAndEmitDynamicWorkerCreationEvents(){this.type===p.dynamic&&this.full&&this.emitter?.emit(y.full,this.info)}getWorkerInfo(e){return this.workerNodes[e]?.info}addWorkerNode(e){const t=new Y(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 node added not found");return s}removeWorkerNode(e){const t=this.getWorkerNodeKeyByWorker(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategyContext.remove(t))}hasWorkerNodeBackPressure(e){return!0===this.opts.enableTasksQueue&&this.workerNodes[e].hasBackPressure()}hasBackPressure(){return!0===this.opts.enableTasksQueue&&-1===this.workerNodes.findIndex((e=>!e.hasBackPressure()))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(e,t,t.transferList),this.checkAndEmitTaskExecutionEvents()}enqueueTask(e,t){const s=this.workerNodes[e].enqueueTask(t);return this.checkAndEmitTaskQueuingEvents(),s}dequeueTask(e){return this.workerNodes[e].dequeueTask()}tasksQueueSize(e){return this.workerNodes[e].tasksQueueSize()}flushTasksQueue(e){for(;this.tasksQueueSize(e)>0;)this.executeTask(e,this.dequeueTask(e));this.workerNodes[e].clearTasksQueue()}flushTasksQueues(){for(const[e]of this.workerNodes.entries())this.flushTasksQueue(e)}}class X extends J{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}setupHook(){a.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return a.isPrimary}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e],s=t.worker,r=new Promise((e=>{s.on("exit",(()=>{e()}))}));s.on("disconnect",(()=>{s.kill()})),await this.sendKillMessageToWorker(e,t.info.id),s.disconnect(),await r}sendToWorker(e,t){this.workerNodes[e].worker.send(t)}sendStartupMessageToWorker(e){this.sendToWorker(e,{ready:!1,workerId:this.workerNodes[e].info.id})}registerWorkerMessageListener(e,t){this.workerNodes[e].worker.on("message",t)}createWorker(){return a.fork(this.opts.env)}get type(){return p.fixed}get worker(){return f.cluster}get busy(){return this.internalBusy()}}class Z extends X{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return p.dynamic}get busy(){return this.full&&this.internalBusy()}}class ee extends J{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}isMain(){return r}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e],s=t.worker,r=new Promise((e=>{s.on("exit",(()=>{e()}))}));await this.sendKillMessageToWorker(e,t.info.id),t.closeChannel(),await s.terminate(),await r}sendToWorker(e,t,s){this.workerNodes[e].messageChannel.port1.postMessage(t,s)}sendStartupMessageToWorker(e){const t=this.workerNodes[e],s=t.worker,r=t.messageChannel.port2;s.postMessage({ready:!1,workerId:t.info.id,port:r},[r])}registerWorkerMessageListener(e,t){this.workerNodes[e].messageChannel.port1.on("message",t)}createWorker(){return new t(this.filePath,{env:i,...this.opts.workerOptions})}get type(){return p.fixed}get worker(){return f.thread}get busy(){return this.internalBusy()}}class te extends ee{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return p.dynamic}get busy(){return this.full&&this.internalBusy()}}const se=6e4,re={killBehavior:M.SOFT,maxInactiveTime:se,killHandler:W};class ie extends m{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,s,r,i=re){if(super(e),this.isMain=t,this.mainWorker=s,this.opts=i,null==this.isMain)throw new Error("isMain parameter is mandatory");this.checkTaskFunctions(r),this.checkWorkerOptions(this.opts),this.isMain||this.getMainWorker().on("message",this.handleReadyMessage.bind(this))}checkWorkerOptions(e){this.opts={...re,...e},delete this.opts.async}checkValidTaskFunction(e,t){if("string"!=typeof e)throw new TypeError("A taskFunctions parameter object key is not a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("A taskFunctions parameter object key is an empty string");if("function"!=typeof t)throw new TypeError("A taskFunctions parameter object value is not a function")}checkTaskFunctions(e){if(null==e)throw new Error("taskFunctions parameter is mandatory");if(this.taskFunctions=new Map,"function"==typeof e){const t=e.bind(this);this.taskFunctions.set(T,t),this.taskFunctions.set("string"==typeof e.name&&e.name.trim().length>0?e.name:"fn1",t)}else{if(!z(e))throw new TypeError("taskFunctions parameter is not a function or a plain object");{let t=!0;for(const[s,r]of Object.entries(e)){this.checkValidTaskFunction(s,r);const e=r.bind(this);t&&(this.taskFunctions.set(T,e),t=!1),this.taskFunctions.set(s,e)}if(t)throw new Error("taskFunctions parameter object is empty")}}}hasTaskFunction(e){return this.checkTaskFunctionName(e),this.taskFunctions.has(e)}addTaskFunction(e,t){if(this.checkTaskFunctionName(e),e===T)throw new Error("Cannot add a task function with the default reserved name");if("function"!=typeof t)throw new TypeError("fn parameter is not a function");try{const s=t.bind(this);return this.taskFunctions.get(e)===this.taskFunctions.get(T)&&this.taskFunctions.set(T,s),this.taskFunctions.set(e,s),this.sendTaskFunctionsListToMainWorker(),!0}catch{return!1}}removeTaskFunction(e){if(this.checkTaskFunctionName(e),e===T)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(T))throw new Error("Cannot remove the task function used as the default task function");const t=this.taskFunctions.delete(e);return this.sendTaskFunctionsListToMainWorker(),t}listTaskFunctions(){const e=[...this.taskFunctions.keys()];let t=T;for(const[e,s]of this.taskFunctions)if(e!==T&&s===this.taskFunctions.get(T)){t=e;break}return[e[e.indexOf(T)],t,...e.filter((e=>e!==T&&e!==t))]}setDefaultTaskFunction(e){if(this.checkTaskFunctionName(e),e===T)throw new Error("Cannot set the default task function reserved name as the default task function");if(!this.taskFunctions.has(e))throw new Error("Cannot set the default task function to a non-existing task function");try{return this.taskFunctions.set(T,this.taskFunctions.get(e)),!0}catch{return!1}}checkTaskFunctionName(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("name parameter is an empty string")}messageListener(e){this.checkMessageWorkerId(e),null!=e.statistics?this.statistics=e.statistics:null!=e.checkActive?e.checkActive?this.startCheckActive():this.stopCheckActive():null!=e.taskId&&null!=e.data?this.run(e):!0===e.kill&&this.handleKillMessage(e)}handleKillMessage(e){if(this.stopCheckActive(),O(this.opts.killHandler))(this.opts.killHandler?.()).then((()=>(this.sendToMainWorker({kill:"success",workerId:this.id}),null))).catch((()=>{this.sendToMainWorker({kill:"failure",workerId:this.id})})).finally((()=>{this.emitDestroy()})).catch(W);else try{this.opts.killHandler?.(),this.sendToMainWorker({kill:"success",workerId:this.id})}catch{this.sendToMainWorker({kill:"failure",workerId:this.id})}finally{this.emitDestroy()}}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Message worker id is not set");if(null!=e.workerId&&e.workerId!==this.id)throw new Error(`Message worker id ${e.workerId} does not match the worker id ${this.id}`)}startCheckActive(){this.lastTaskTimestamp=c.now(),this.activeInterval=setInterval(this.checkActive.bind(this),(this.opts.maxInactiveTime??se)/2)}stopCheckActive(){null!=this.activeInterval&&(clearInterval(this.activeInterval),delete this.activeInterval)}checkActive(){c.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??se)&&this.sendToMainWorker({kill:this.opts.killBehavior,workerId:this.id})}getMainWorker(){if(null==this.mainWorker)throw new Error("Main worker not set");return this.mainWorker}sendTaskFunctionsListToMainWorker(){this.sendToMainWorker({taskFunctions:this.listTaskFunctions(),workerId:this.id})}handleError(e){return e instanceof Error?e.message:e}run(e){const{name:t,taskId:s,data:r}=e,i=this.taskFunctions.get(t??T);null!=i?O(i)?this.runInAsyncScope(this.runAsync.bind(this),this,i,e):this.runInAsyncScope(this.runSync.bind(this),this,i,e):this.sendToMainWorker({taskError:{name:t,message:`Task function '${t}' not found`,data:r},workerId:this.id,taskId:s})}runSync(e,t){const{name:s,taskId:r,data:i}=t;try{let t=this.beginTaskPerformance(s);const o=e(i);t=this.endTaskPerformance(t),this.sendToMainWorker({data:o,taskPerformance:t,workerId:this.id,taskId:r})}catch(e){const t=this.handleError(e);this.sendToMainWorker({taskError:{name:s,message:t,data:i},workerId:this.id,taskId:r})}finally{this.updateLastTaskTimestamp()}}runAsync(e,t){const{name:s,taskId:r,data:i}=t;let o=this.beginTaskPerformance(s);e(i).then((e=>(o=this.endTaskPerformance(o),this.sendToMainWorker({data:e,taskPerformance:o,workerId:this.id,taskId:r}),null))).catch((e=>{const t=this.handleError(e);this.sendToMainWorker({taskError:{name:s,message:t,data:i},workerId:this.id,taskId:r})})).finally((()=>{this.updateLastTaskTimestamp()})).catch(W)}beginTaskPerformance(e){return this.checkStatistics(),{name:e??T,timestamp:c.now(),...this.statistics.elu&&{elu:c.eventLoopUtilization()}}}endTaskPerformance(e){return this.checkStatistics(),{...e,...this.statistics.runTime&&{runTime:c.now()-e.timestamp},...this.statistics.elu&&{elu:c.eventLoopUtilization(e.elu)}}}checkStatistics(){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set")}updateLastTaskTimestamp(){null!=this.activeInterval&&(this.lastTaskTimestamp=c.now())}}class oe extends ie{constructor(e,t={}){super("worker-cluster-pool:poolifier",a.isPrimary,a.worker,e,t)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready)try{this.getMainWorker().on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctions:this.listTaskFunctions(),workerId:this.id})}catch{this.sendToMainWorker({ready:!1,taskFunctions:this.listTaskFunctions(),workerId:this.id})}}get id(){return this.getMainWorker().id}sendToMainWorker(e){this.getMainWorker().send(e)}}class ne extends ie{port;constructor(e,t={}){super("worker-thread-pool:poolifier",r,o,e,t)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready&&null!=e.port)try{this.port=e.port,this.port.on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctions:this.listTaskFunctions(),workerId:this.id})}catch{this.sendToMainWorker({ready:!1,taskFunctions:this.listTaskFunctions(),workerId:this.id})}}handleKillMessage(e){super.handleKillMessage(e),this.port?.unref(),this.port?.close()}get id(){return n}sendToMainWorker(e){this.port.postMessage(e)}handleError(e){return e}}export{oe as ClusterWorker,Z as DynamicClusterPool,te as DynamicThreadPool,X as FixedClusterPool,ee as FixedThreadPool,M as KillBehaviors,q as Measurements,y as PoolEvents,p as PoolTypes,ne as ThreadWorker,K as WorkerChoiceStrategies,f as WorkerTypes,S as availableParallelism};
@@ -146,6 +146,7 @@ export declare abstract class AbstractPool<Worker extends IWorker, Data = unknow
146
146
  protected internalBusy(): boolean;
147
147
  /** @inheritDoc */
148
148
  listTaskFunctions(): string[];
149
+ private shallExecuteTask;
149
150
  /** @inheritDoc */
150
151
  execute(data?: Data, name?: string, transferList?: TransferListItem[]): Promise<Response>;
151
152
  /** @inheritDoc */
@@ -262,6 +263,7 @@ export declare abstract class AbstractPool<Worker extends IWorker, Data = unknow
262
263
  */
263
264
  private sendStatisticsMessageToWorker;
264
265
  private redistributeQueuedTasks;
266
+ private updateTaskStolenStatisticsWorkerUsage;
265
267
  private taskStealingOnEmptyQueue;
266
268
  private tasksStealingOnBackPressure;
267
269
  /**
@@ -187,7 +187,7 @@ export interface IPool<Worker extends IWorker, Data = unknown, Response = unknow
187
187
  * Events that can currently be listened to:
188
188
  *
189
189
  * - `'ready'`: Emitted when the number of workers created in the pool has reached the minimum size expected and are ready.
190
- * - `'busy'`: Emitted when the number of workers created in the pool has reached the maximum size expected and are executing at least one task.
190
+ * - `'busy'`: Emitted when the number of workers created in the pool has reached the maximum size expected and are executing concurrently their tasks quota.
191
191
  * - `'full'`: Emitted when the pool is dynamic and the number of workers created has reached the maximum size expected.
192
192
  * - `'destroy'`: Emitted when the pool is destroyed.
193
193
  * - `'error'`: Emitted when an uncaught error occurs.
@@ -67,7 +67,7 @@ export interface WorkerChoiceStrategyOptions {
67
67
  *
68
68
  * @defaultValue 6
69
69
  */
70
- readonly choiceRetries?: number;
70
+ readonly retries?: number;
71
71
  /**
72
72
  * Measurement to use in worker choice strategy supporting it.
73
73
  */
@@ -15,7 +15,7 @@ export declare class WorkerChoiceStrategyContext<Worker extends IWorker, Data =
15
15
  /**
16
16
  * The number of times the worker choice strategy in the context has been retried.
17
17
  */
18
- private choiceRetriesCount;
18
+ private retriesCount;
19
19
  /**
20
20
  * Worker choice strategy context constructor.
21
21
  *
@@ -1 +1 @@
1
- export declare const version = "2.6.36";
1
+ export declare const version = "2.6.37";
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import { MessageChannel } from 'node:worker_threads';
3
3
  import type { Task } from '../utility-types';
4
- import { type IWorker, type IWorkerNode, type WorkerInfo, type WorkerType, type WorkerUsage } from './worker';
4
+ import { type IWorker, type IWorkerNode, type WorkerInfo, type WorkerNodeEventCallback, type WorkerUsage } from './worker';
5
5
  /**
6
6
  * Worker node.
7
7
  *
@@ -20,9 +20,9 @@ export declare class WorkerNode<Worker extends IWorker, Data = unknown> implemen
20
20
  /** @inheritdoc */
21
21
  tasksQueueBackPressureSize: number;
22
22
  /** @inheritdoc */
23
- onBackPressure?: (workerId: number) => void;
23
+ onBackPressure?: WorkerNodeEventCallback;
24
24
  /** @inheritdoc */
25
- onEmptyQueue?: (workerId: number) => void;
25
+ onEmptyQueue?: WorkerNodeEventCallback;
26
26
  private readonly tasksQueue;
27
27
  private onEmptyQueueCount;
28
28
  private readonly taskFunctionsUsage;
@@ -30,10 +30,9 @@ export declare class WorkerNode<Worker extends IWorker, Data = unknown> implemen
30
30
  * Constructs a new worker node.
31
31
  *
32
32
  * @param worker - The worker.
33
- * @param workerType - The worker type.
34
33
  * @param tasksQueueBackPressureSize - The tasks queue back pressure size.
35
34
  */
36
- constructor(worker: Worker, workerType: WorkerType, tasksQueueBackPressureSize: number);
35
+ constructor(worker: Worker, tasksQueueBackPressureSize: number);
37
36
  /** @inheritdoc */
38
37
  tasksQueueSize(): number;
39
38
  /** @inheritdoc */
@@ -58,12 +57,4 @@ export declare class WorkerNode<Worker extends IWorker, Data = unknown> implemen
58
57
  private initWorkerInfo;
59
58
  private initWorkerUsage;
60
59
  private initTaskFunctionWorkerUsage;
61
- /**
62
- * Gets the worker id.
63
- *
64
- * @param worker - The worker.
65
- * @param workerType - The worker type.
66
- * @returns The worker id.
67
- */
68
- private getWorkerId;
69
60
  }
@@ -175,6 +175,7 @@ export interface IWorker {
175
175
  */
176
176
  readonly once: (event: 'exit', handler: ExitHandler<this>) => void;
177
177
  }
178
+ export type WorkerNodeEventCallback = (workerId: number) => void;
178
179
  /**
179
180
  * Worker node interface.
180
181
  *
@@ -209,13 +210,13 @@ export interface IWorkerNode<Worker extends IWorker, Data = unknown> {
209
210
  *
210
211
  * @param workerId - The worker id.
211
212
  */
212
- onBackPressure?: (workerId: number) => void;
213
+ onBackPressure?: WorkerNodeEventCallback;
213
214
  /**
214
215
  * Callback invoked when worker node tasks queue is empty.
215
216
  *
216
217
  * @param workerId - The worker id.
217
218
  */
218
- onEmptyQueue?: (workerId: number) => void;
219
+ onEmptyQueue?: WorkerNodeEventCallback;
219
220
  /**
220
221
  * Tasks queue size.
221
222
  *
package/lib/utils.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { MeasurementStatisticsRequirements, WorkerChoiceStrategyOptions } from './pools/selection-strategies/selection-strategies-types';
2
- import type { MeasurementStatistics } from './pools/worker';
2
+ import { type IWorker, type MeasurementStatistics, type WorkerType } from './pools/worker';
3
3
  /**
4
4
  * Default task name.
5
5
  */
@@ -24,6 +24,22 @@ export declare const DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS: MeasurementSta
24
24
  * @internal
25
25
  */
26
26
  export declare const availableParallelism: () => number;
27
+ /**
28
+ * Returns the worker type of the given worker.
29
+ *
30
+ * @param worker - The worker to get the type of.
31
+ * @returns The worker type of the given worker.
32
+ * @internal
33
+ */
34
+ export declare const getWorkerType: <Worker_1 extends IWorker>(worker: Worker_1) => WorkerType | undefined;
35
+ /**
36
+ * Returns the worker id of the given worker.
37
+ *
38
+ * @param worker - The worker to get the id of.
39
+ * @returns The worker id of the given worker.
40
+ * @internal
41
+ */
42
+ export declare const getWorkerId: <Worker_1 extends IWorker>(worker: Worker_1) => number | undefined;
27
43
  /**
28
44
  * Sleeps for the given amount of milliseconds.
29
45
  *
@@ -99,14 +115,6 @@ export declare const isAsyncFunction: (fn: unknown) => fn is (...args: unknown[]
99
115
  * @internal
100
116
  */
101
117
  export declare const updateMeasurementStatistics: (measurementStatistics: MeasurementStatistics, measurementRequirements: MeasurementStatisticsRequirements, measurementValue: number) => void;
102
- /**
103
- * Executes a function once at a time.
104
- *
105
- * @param fn - The function to execute.
106
- * @param context - The context to bind the function to.
107
- * @returns The function to execute.
108
- */
109
- export declare const once: (fn: (...args: any[]) => void, context: unknown) => (...args: any[]) => void;
110
118
  /**
111
119
  * Generate a cryptographically secure random number in the [0,1[ range
112
120
  *
@@ -50,6 +50,7 @@ export declare abstract class AbstractWorker<MainWorker extends Worker | Message
50
50
  */
51
51
  constructor(type: string, isMain: boolean, mainWorker: MainWorker, taskFunctions: TaskFunction<Data, Response> | TaskFunctions<Data, Response>, opts?: WorkerOptions);
52
52
  private checkWorkerOptions;
53
+ private checkValidTaskFunction;
53
54
  /**
54
55
  * Checks if the `taskFunctions` parameter is passed to the constructor.
55
56
  *
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "poolifier",
4
- "version": "2.6.36",
4
+ "version": "2.6.37",
5
5
  "description": "Fast and small Node.js Worker_Threads and Cluster Worker Pool",
6
6
  "license": "MIT",
7
7
  "main": "./lib/index.js",
@@ -85,14 +85,14 @@
85
85
  "@release-it/keep-a-changelog": "^4.0.0",
86
86
  "@rollup/plugin-terser": "^0.4.3",
87
87
  "@rollup/plugin-typescript": "^11.1.3",
88
- "@types/node": "^20.5.6",
89
- "@typescript-eslint/eslint-plugin": "^6.4.1",
90
- "@typescript-eslint/parser": "^6.4.1",
88
+ "@types/node": "^20.5.7",
89
+ "@typescript-eslint/eslint-plugin": "^6.5.0",
90
+ "@typescript-eslint/parser": "^6.5.0",
91
91
  "benny": "^3.7.1",
92
92
  "c8": "^8.0.1",
93
93
  "eslint": "^8.48.0",
94
94
  "eslint-config-standard": "^17.1.0",
95
- "eslint-config-standard-with-typescript": "^38.0.0",
95
+ "eslint-config-standard-with-typescript": "^39.0.0",
96
96
  "eslint-define-config": "^1.23.0",
97
97
  "eslint-import-resolver-typescript": "^3.6.0",
98
98
  "eslint-plugin-import": "^2.28.1",