poolifier 2.6.14 → 2.6.15
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/README.md +3 -3
- package/lib/index.js +1 -1
- package/lib/index.mjs +1 -1
- package/lib/pools/abstract-pool.d.ts +31 -18
- package/lib/pools/selection-strategies/abstract-worker-choice-strategy.d.ts +3 -2
- package/lib/pools/selection-strategies/fair-share-worker-choice-strategy.d.ts +1 -0
- package/lib/pools/selection-strategies/least-busy-worker-choice-strategy.d.ts +1 -0
- package/lib/pools/selection-strategies/least-elu-worker-choice-strategy.d.ts +1 -0
- package/lib/pools/selection-strategies/least-used-worker-choice-strategy.d.ts +1 -0
- package/lib/pools/selection-strategies/round-robin-worker-choice-strategy.d.ts +1 -0
- package/lib/pools/selection-strategies/selection-strategies-types.d.ts +1 -1
- package/lib/pools/selection-strategies/weighted-round-robin-worker-choice-strategy.d.ts +1 -0
- package/lib/pools/version.d.ts +1 -1
- package/lib/pools/worker.d.ts +1 -1
- package/lib/utility-types.d.ts +4 -4
- package/lib/worker/abstract-worker.d.ts +10 -10
- package/lib/worker/worker-options.d.ts +4 -4
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -244,13 +244,13 @@ This method is available on both pool implementations and will call the terminat
|
|
|
244
244
|
`taskFunctions` (mandatory) The task function or task functions object `{ name_1: fn_1, ..., name_n: fn_n }` that you want to execute on the worker
|
|
245
245
|
`opts` (optional) An object with these properties:
|
|
246
246
|
|
|
247
|
-
- `maxInactiveTime` (optional) -
|
|
248
|
-
The last active time of your worker
|
|
247
|
+
- `maxInactiveTime` (optional) - Maximum waiting time in milliseconds for tasks on newly created workers. After this time newly created workers will die.
|
|
248
|
+
The last active time of your worker will be updated when it terminates a task.
|
|
249
249
|
If `killBehavior` is set to `KillBehaviors.HARD` this value represents also the timeout for the tasks that you submit to the pool, when this timeout expires your tasks is interrupted before completion and removed. The worker is killed if is not part of the minimum size of the pool.
|
|
250
250
|
If `killBehavior` is set to `KillBehaviors.SOFT` your tasks have no timeout and your workers will not be terminated until your task is completed.
|
|
251
251
|
Default: `60000`
|
|
252
252
|
|
|
253
|
-
- `killBehavior` (optional) - Dictates if your
|
|
253
|
+
- `killBehavior` (optional) - Dictates if your worker will be deleted in case a task is active on it.
|
|
254
254
|
**KillBehaviors.SOFT**: If `currentTime - lastActiveTime` is greater than `maxInactiveTime` but a task is still executing or queued, then the worker **won't** be deleted.
|
|
255
255
|
**KillBehaviors.HARD**: If `currentTime - lastActiveTime` is greater than `maxInactiveTime` but a task is still executing or queued, then the worker will be deleted.
|
|
256
256
|
This option only apply to the newly created workers.
|
package/lib/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("node:events"),t=require("node:cluster"),s=require("node:crypto"),r=require("node:perf_hooks"),i=require("node:os"),o=require("node:worker_threads"),a=require("node:async_hooks");function n(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=n(i);const h=Object.freeze({fixed:"fixed",dynamic:"dynamic"});class k extends e.EventEmitter{}const c=Object.freeze({full:"full",ready:"ready",busy:"busy",error:"error",taskError:"taskError"}),d="default",m=Object.freeze((()=>{})),l={runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},g={aggregate:!1,average:!1,median:!1},p=e=>{if(Array.isArray(e)&&0===e.length)return 0;if(Array.isArray(e)&&1===e.length)return e[0];const t=e.slice().sort(((e,t)=>e-t));return(t[t.length-1>>1]+t[t.length>>1])/2},w=(e,t=2)=>{const s=Math.pow(10,t);return Math.round(e*s*(1+Number.EPSILON))/s},T=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),f=Object.freeze({SOFT:"SOFT",HARD:"HARD"}),y=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"}),W=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"});class S{pool;opts;nextWorkerNodeId=0;strategyPolicy={useDynamicWorker:!1};taskStatisticsRequirements={runTime:g,waitTime:g,elu:g};constructor(e,t=l){this.pool=e,this.opts=t,this.choose=this.choose.bind(this)}setTaskStatisticsRequirements(e){this.taskStatisticsRequirements.runTime.average&&!0===e.runTime?.median&&(this.taskStatisticsRequirements.runTime.average=!1,this.taskStatisticsRequirements.runTime.median=e.runTime.median),this.taskStatisticsRequirements.runTime.median&&!1===e.runTime?.median&&(this.taskStatisticsRequirements.runTime.average=!0,this.taskStatisticsRequirements.runTime.median=e.runTime.median),this.taskStatisticsRequirements.waitTime.average&&!0===e.waitTime?.median&&(this.taskStatisticsRequirements.waitTime.average=!1,this.taskStatisticsRequirements.waitTime.median=e.waitTime.median),this.taskStatisticsRequirements.waitTime.median&&!1===e.waitTime?.median&&(this.taskStatisticsRequirements.waitTime.average=!0,this.taskStatisticsRequirements.waitTime.median=e.waitTime.median),this.taskStatisticsRequirements.elu.average&&!0===e.elu?.median&&(this.taskStatisticsRequirements.elu.average=!1,this.taskStatisticsRequirements.elu.median=e.elu.median),this.taskStatisticsRequirements.elu.median&&!1===e.elu?.median&&(this.taskStatisticsRequirements.elu.average=!0,this.taskStatisticsRequirements.elu.median=e.elu.median)}setOptions(e){this.opts=e??l,this.setTaskStatisticsRequirements(this.opts)}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}computeDefaultWorkerWeight(){let e=0;for(const t of i.cpus()){const s=t.speed.toString().length-1;e+=1/(t.speed/Math.pow(10,s))*Math.pow(10,s)}return Math.round(e/i.cpus().length)}}class x extends S{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:g,elu:{aggregate:!0,average:!0,median:!1}};workersVirtualTaskEndTimestamp=[];constructor(e,t=l){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.workersVirtualTaskEndTimestamp=[],!0}update(e){return this.computeWorkerVirtualTaskEndTimestamp(e),!0}choose(){let e=1/0;for(const[t]of this.pool.workerNodes.entries()){null==this.workersVirtualTaskEndTimestamp[t]&&this.computeWorkerVirtualTaskEndTimestamp(t);const s=this.workersVirtualTaskEndTimestamp[t];s<e&&(e=s,this.nextWorkerNodeId=t)}return this.nextWorkerNodeId}remove(e){return this.workersVirtualTaskEndTimestamp.splice(e,1),!0}computeWorkerVirtualTaskEndTimestamp(e){this.workersVirtualTaskEndTimestamp[e]=this.getWorkerVirtualTaskEndTimestamp(e,this.getWorkerVirtualTaskStartTimestamp(e))}getWorkerVirtualTaskEndTimestamp(e,t){return t+(this.opts.measurement===W.elu?this.getWorkerTaskElu(e):this.getWorkerTaskRunTime(e))}getWorkerVirtualTaskStartTimestamp(e){return Math.max(performance.now(),this.workersVirtualTaskEndTimestamp[e]??-1/0)}}class N extends S{strategyPolicy={useDynamicWorker:!0};roundId=0;roundWeights;defaultWorkerWeight;constructor(e,t=l){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight(),this.roundWeights=this.getRoundWeights()}reset(){return this.nextWorkerNodeId=0,this.roundId=0,!0}update(){return!0}choose(){let e,t;for(let s=this.roundId;s<this.roundWeights.length;s++)for(let r=this.nextWorkerNodeId;r<this.pool.workerNodes.length;r++){if((this.opts.weights?.[r]??this.defaultWorkerWeight)>=this.roundWeights[s]){e=s,t=r;break}}this.roundId=e??0,this.nextWorkerNodeId=t??0;const s=this.nextWorkerNodeId;return this.nextWorkerNodeId===this.pool.workerNodes.length-1?(this.nextWorkerNodeId=0,this.roundId=this.roundId===this.roundWeights.length-1?0:this.roundId+1):this.nextWorkerNodeId=this.nextWorkerNodeId+1,s}remove(e){return this.nextWorkerNodeId===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeId=0:this.nextWorkerNodeId>this.pool.workerNodes.length-1&&(this.nextWorkerNodeId=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 v extends S{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:g};constructor(e,t=l){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=(s.usage.runTime?.aggregate??0)+(s.usage.waitTime?.aggregate??0);if(0===r){this.nextWorkerNodeId=t;break}r<e&&(e=r,this.nextWorkerNodeId=t)}return this.nextWorkerNodeId}remove(){return!0}}class I extends S{constructor(e,t=l){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=s.usage.tasks,i=r.executed+r.executing+r.queued;if(0===i){this.nextWorkerNodeId=t;break}i<e&&(e=i,this.nextWorkerNodeId=t)}return this.nextWorkerNodeId}remove(){return!0}}class E extends S{taskStatisticsRequirements={runTime:g,waitTime:g,elu:{aggregate:!0,average:!1,median:!1}};constructor(e,t=l){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=s.usage,i=r.elu?.active?.aggregate??0;if(0===i){this.nextWorkerNodeId=t;break}i<e&&(e=i,this.nextWorkerNodeId=t)}return this.nextWorkerNodeId}remove(){return!0}}class R extends S{strategyPolicy={useDynamicWorker:!0};constructor(e,t=l){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.nextWorkerNodeId=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeId;return this.nextWorkerNodeId=this.nextWorkerNodeId===this.pool.workerNodes.length-1?0:this.nextWorkerNodeId+1,e}remove(e){return this.nextWorkerNodeId===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeId=0:this.nextWorkerNodeId>this.pool.workerNodes.length-1&&(this.nextWorkerNodeId=this.pool.workerNodes.length-1)),!0}}class b extends S{strategyPolicy={useDynamicWorker:!0};taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:g,elu:g};defaultWorkerWeight;workerVirtualTaskRunTime=0;constructor(e,t=l){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight()}reset(){return this.nextWorkerNodeId=0,this.workerVirtualTaskRunTime=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeId,t=this.workerVirtualTaskRunTime;return t<(this.opts.weights?.[e]??this.defaultWorkerWeight)?this.workerVirtualTaskRunTime=t+this.getWorkerTaskRunTime(e):(this.nextWorkerNodeId=this.nextWorkerNodeId===this.pool.workerNodes.length-1?0:this.nextWorkerNodeId+1,this.workerVirtualTaskRunTime=0),e}remove(e){return this.nextWorkerNodeId===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeId=0:this.nextWorkerNodeId>this.pool.workerNodes.length-1&&(this.nextWorkerNodeId=this.pool.workerNodes.length-1),this.workerVirtualTaskRunTime=0),!0}}class C{workerChoiceStrategy;workerChoiceStrategies;constructor(e,t=y.ROUND_ROBIN,s=l){this.workerChoiceStrategy=t,this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[y.ROUND_ROBIN,new(R.bind(this))(e,s)],[y.LEAST_USED,new(I.bind(this))(e,s)],[y.LEAST_BUSY,new(v.bind(this))(e,s)],[y.LEAST_ELU,new(E.bind(this))(e,s)],[y.FAIR_SHARE,new(x.bind(this))(e,s)],[y.WEIGHTED_ROUND_ROBIN,new(b.bind(this))(e,s)],[y.INTERLEAVED_WEIGHTED_ROUND_ROBIN,new(N.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)throw new Error("Worker node key chosen is null or undefined");return e}remove(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).remove(e)}setOptions(e){for(const t of this.workerChoiceStrategies.values())t.setOptions(e)}}class O 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;return arguments.length>=3&&void 0!==t?(r=super.splice(e,t),this.push(...s)):r=2===arguments.length?super.splice(e,t):super.splice(e),r}resize(e){if(this.checkSize(e),0===e)this.length=0;else if(e<this.size)for(let t=e;t<this.size;t++)super.pop();this.size=e}empty(){return 0===this.length}full(){return this.length===this.size}checkSize(e){if(!Number.isSafeInteger(e))throw new TypeError(`Invalid circular array size: ${e} is not a safe integer`);if(e<0)throw new RangeError(`Invalid circular array size: ${e} < 0`)}}class z{items;offset;size;maxSize;constructor(){this.clear()}enqueue(e){return this.items.push(e),++this.size,this.size>this.maxSize&&(this.maxSize=this.size),this.size}dequeue(){if(this.size<=0)return;const e=this.items[this.offset];return 2*++this.offset>=this.items.length&&(this.items=this.items.slice(this.offset),this.offset=0),--this.size,e}peek(){if(!(this.size<=0))return this.items[this.offset]}clear(){this.items=[],this.offset=0,this.size=0,this.maxSize=0}[Symbol.iterator](){const e=this.items;let t=this.offset;return{next:()=>{if(t>=e.length)return{value:void 0,done:!0};const s=e[t];return++t,{value:s,done:!1}}}}}const q=Object.freeze({cluster:"cluster",thread:"thread"});class M{worker;info;usage;tasksUsage;tasksQueue;constructor(e,t){this.worker=e,this.info=this.initWorkerInfo(e,t),this.usage=this.initWorkerUsage(),this.tasksUsage=new Map,this.tasksQueue=new z}tasksQueueSize(){return this.tasksQueue.size}tasksQueueMaxSize(){return this.tasksQueue.maxSize}enqueueTask(e){return this.tasksQueue.enqueue(e)}dequeueTask(){return this.tasksQueue.dequeue()}clearTasksQueue(){this.tasksQueue.clear()}resetUsage(){this.usage=this.initWorkerUsage(),this.tasksUsage.clear()}getTaskWorkerUsage(e){return this.tasksUsage.has(e)||this.tasksUsage.set(e,this.initTaskWorkerUsage(e)),this.tasksUsage.get(e)}initWorkerInfo(e,t){return{id:this.getWorkerId(e,t),type:t,dynamic:!1,ready:!1}}initWorkerUsage(){const e=()=>this.tasksQueueSize(),t=()=>this.tasksQueueMaxSize();return{tasks:{executed:0,executing:0,get queued(){return e()},get maxQueued(){return t()},failed:0},runTime:{history:new O},waitTime:{history:new O},elu:{idle:{history:new O},active:{history:new O}}}}initTaskWorkerUsage(e){const t=()=>{let t=0;for(const s of this.tasksQueue)s.name===e&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},failed:0},runTime:{history:new O},waitTime:{history:new O},elu:{idle:{history:new O},active:{history:new O}}}}getWorkerId(e,t){return t===q.thread?e.threadId:t===q.cluster?e.id:void 0}}class P{numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;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!");for(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),this.checkAndEmitEvents=this.checkAndEmitEvents.bind(this),!0===this.opts.enableEvents&&(this.emitter=new k),this.workerChoiceStrategyContext=new C(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook();this.workerNodes.length<this.numberOfWorkers;)this.createAndSetupWorker();this.startTimestamp=r.performance.now()}checkFilePath(e){if(null==e||"string"==typeof e&&0===e.trim().length)throw new Error("Please specify a file with a worker implementation")}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===h.fixed&&0===e)throw new RangeError("Cannot instantiate a fixed pool with zero worker")}checkDynamicPoolSize(e,t){if(this.type===h.dynamic){if(e>t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size");if(0===e&&0===t)throw new RangeError("Cannot instantiate a dynamic pool with a minimum pool size and 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??y.ROUND_ROBIN,this.checkValidWorkerChoiceStrategy(this.opts.workerChoiceStrategy),this.opts.workerChoiceStrategyOptions=e.workerChoiceStrategyOptions??l,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(y).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.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(W).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 tasks concurrency: must be an integer");if(null!=e?.concurrency&&e.concurrency<=0)throw new Error(`Invalid worker tasks concurrency '${e.concurrency}'`)}get info(){return{version:"2.6.14",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:w(this.utilization)},workerNodes:this.workerNodes.length,idleWorkerNodes:this.workerNodes.reduce(((e,t)=>0===t.usage.tasks.executing?e+1:e),0),busyWorkerNodes:this.workerNodes.reduce(((e,t)=>t.usage.tasks.executing>0?e+1:e),0),executedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executed),0),executingTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executing),0),queuedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.queued),0),maxQueuedTasks:this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.maxQueued??0)),0),failedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.failed),0),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&{runTime:{minimum:w(Math.min(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:w(Math.max(...this.workerNodes.map((e=>e.usage.runTime?.maximum??-1/0)))),average:w(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)/this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.executed??0)),0)),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&{median:w(p(this.workerNodes.map((e=>e.usage.runTime?.median??0))))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:w(Math.min(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:w(Math.max(...this.workerNodes.map((e=>e.usage.waitTime?.maximum??-1/0)))),average:w(this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0)/this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.executed??0)),0)),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&{median:w(p(this.workerNodes.map((e=>e.usage.waitTime?.median??0))))}}}}}get starting(){return this.workerNodes.length<this.minSize||this.workerNodes.length>=this.minSize&&this.workerNodes.some((e=>!e.info.ready))}get ready(){return this.workerNodes.length>=this.minSize&&this.workerNodes.every((e=>e.info.ready))}get utilization(){const e=(r.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}getWorkerById(e){return this.workerNodes.find((t=>t.info.id===e))?.worker}checkMessageWorkerId(e){if(null!=e.workerId&&null==this.getWorkerById(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKey(e){return this.workerNodes.findIndex((t=>t.worker===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 of this.workerNodes)e.resetUsage(),this.setWorkerStatistics(e.worker)}setWorkerChoiceStrategyOptions(e){this.checkValidWorkerChoiceStrategyOptions(e),this.opts.workerChoiceStrategyOptions=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)):null!=this.opts.tasksQueueOptions&&delete this.opts.tasksQueueOptions}buildTasksQueueOptions(e){return{concurrency:e?.concurrency??1}}get full(){return this.workerNodes.length>=this.maxSize}internalBusy(){return-1===this.workerNodes.findIndex((e=>0===e.usage.tasks.executing))}async execute(e,t){const i=r.performance.now(),o=this.chooseWorkerNode(),a={name:t??d,data:e??{},timestamp:i,workerId:this.getWorkerInfo(o).id,id:s.randomUUID()},n=new Promise(((e,t)=>{this.promiseResponseMap.set(a.id,{resolve:e,reject:t,worker:this.workerNodes[o].worker})}));return!0===this.opts.enableTasksQueue&&(this.busy||this.workerNodes[o].usage.tasks.executing>=this.opts.tasksQueueOptions.concurrency)?this.enqueueTask(o,a):this.executeTask(o,a),this.checkAndEmitEvents(),n}async destroy(){await Promise.all(this.workerNodes.map((async(e,t)=>{this.flushTasksQueue(t);const s=new Promise((t=>{e.worker.on("exit",(()=>{t()}))}));await this.destroyWorker(e.worker),await s})))}setupHook(){}beforeTaskExecutionHook(e,t){const s=this.workerNodes[e].usage;++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t);const r=this.workerNodes[e].getTaskWorkerUsage(t.name);++r.tasks.executing,this.updateWaitTimeWorkerUsage(r,t)}afterTaskExecutionHook(e,t){const s=this.getWorkerNodeKey(e),r=this.workerNodes[s].usage;this.updateTaskStatisticsWorkerUsage(r,t),this.updateRunTimeWorkerUsage(r,t),this.updateEluWorkerUsage(r,t);const i=this.workerNodes[s].getTaskWorkerUsage(t.taskPerformance?.name??d);this.updateTaskStatisticsWorkerUsage(i,t),this.updateRunTimeWorkerUsage(i,t),this.updateEluWorkerUsage(i,t)}updateTaskStatisticsWorkerUsage(e,t){const s=e.tasks;--s.executing,null==t.taskError?++s.executed:++s.failed}updateRunTimeWorkerUsage(e,t){if(this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate){const s=t.taskPerformance?.runTime??0;e.runTime.aggregate=(e.runTime.aggregate??0)+s,e.runTime.minimum=Math.min(s,e.runTime?.minimum??1/0),e.runTime.maximum=Math.max(s,e.runTime?.maximum??-1/0),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.average&&0!==e.tasks.executed&&(e.runTime.average=e.runTime.aggregate/e.tasks.executed),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&null!=t.taskPerformance?.runTime&&(e.runTime.history.push(t.taskPerformance.runTime),e.runTime.median=p(e.runTime.history))}}updateWaitTimeWorkerUsage(e,t){const s=r.performance.now(),i=s-(t.timestamp??s);this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&(e.waitTime.aggregate=(e.waitTime?.aggregate??0)+i,e.waitTime.minimum=Math.min(i,e.waitTime?.minimum??1/0),e.waitTime.maximum=Math.max(i,e.waitTime?.maximum??-1/0),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.average&&0!==e.tasks.executed&&(e.waitTime.average=e.waitTime.aggregate/e.tasks.executed),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&(e.waitTime.history.push(i),e.waitTime.median=p(e.waitTime.history)))}updateEluWorkerUsage(e,t){this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate&&null!=t.taskPerformance?.elu&&(e.elu.idle.aggregate=(e.elu.idle?.aggregate??0)+t.taskPerformance.elu.idle,e.elu.active.aggregate=(e.elu.active?.aggregate??0)+t.taskPerformance.elu.active,null!=e.elu.utilization?e.elu.utilization=(e.elu.utilization+t.taskPerformance.elu.utilization)/2:e.elu.utilization=t.taskPerformance.elu.utilization,e.elu.idle.minimum=Math.min(t.taskPerformance.elu.idle,e.elu.idle?.minimum??1/0),e.elu.idle.maximum=Math.max(t.taskPerformance.elu.idle,e.elu.idle?.maximum??-1/0),e.elu.active.minimum=Math.min(t.taskPerformance.elu.active,e.elu.active?.minimum??1/0),e.elu.active.maximum=Math.max(t.taskPerformance.elu.active,e.elu.active?.maximum??-1/0),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.average&&0!==e.tasks.executed&&(e.elu.idle.average=e.elu.idle.aggregate/e.tasks.executed,e.elu.active.average=e.elu.active.aggregate/e.tasks.executed),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.median&&(e.elu.idle.history.push(t.taskPerformance.elu.idle),e.elu.active.history.push(t.taskPerformance.elu.active),e.elu.idle.median=p(e.elu.idle.history),e.elu.active.median=p(e.elu.active.history)))}chooseWorkerNode(){if(this.shallCreateDynamicWorker()){const e=this.createAndSetupDynamicWorker();if(this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker)return this.getWorkerNodeKey(e)}return this.workerChoiceStrategyContext.execute()}shallCreateDynamicWorker(){return this.type===h.dynamic&&!this.full&&this.internalBusy()}registerWorkerMessageListener(e,t){e.on("message",t)}afterWorkerSetup(e){this.registerWorkerMessageListener(e,this.workerListener()),this.sendToWorker(e,{ready:!1,workerId:this.getWorkerInfo(this.getWorkerNodeKey(e)).id}),this.setWorkerStatistics(e)}createAndSetupWorker(){const e=this.createWorker();return e.on("message",this.opts.messageHandler??m),e.on("error",this.opts.errorHandler??m),e.on("error",(t=>{null!=this.emitter&&this.emitter.emit(c.error,t),!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(e),!0!==this.opts.restartWorkerOnError||this.starting||(this.getWorkerInfo(this.getWorkerNodeKey(e)).dynamic?this.createAndSetupDynamicWorker():this.createAndSetupWorker())})),e.on("online",this.opts.onlineHandler??m),e.on("exit",this.opts.exitHandler??m),e.once("exit",(()=>{this.removeWorkerNode(e)})),this.pushWorkerNode(e),this.afterWorkerSetup(e),e}redistributeQueuedTasks(e){const t=this.getWorkerNodeKey(e);for(;this.tasksQueueSize(t)>0;){let e=t,s=1/0;for(const[r,i]of this.workerNodes.entries()){if(r!==t&&0===i.usage.tasks.queued){e=r;break}r!==t&&i.usage.tasks.queued<s&&(s=i.usage.tasks.queued,e=r)}this.enqueueTask(e,this.dequeueTask(t))}}createAndSetupDynamicWorker(){const e=this.createAndSetupWorker();this.registerWorkerMessageListener(e,(t=>{const s=this.getWorkerNodeKey(e);var r;r=f.HARD,(t.kill===r||null!=t.kill&&(!1===this.opts.enableTasksQueue&&0===this.workerNodes[s].usage.tasks.executing||!0===this.opts.enableTasksQueue&&0===this.workerNodes[s].usage.tasks.executing&&0===this.tasksQueueSize(s)))&&this.destroyWorker(e)}));const t=this.getWorkerInfo(this.getWorkerNodeKey(e));return t.dynamic=!0,this.sendToWorker(e,{checkAlive:!0,workerId:t.id}),e}workerListener(){return e=>{this.checkMessageWorkerId(e),null!=e.ready&&null!=e.workerId?this.handleWorkerReadyMessage(e):null!=e.id&&this.handleTaskExecutionResponse(e)}}handleWorkerReadyMessage(e){const t=this.getWorkerById(e.workerId);this.getWorkerInfo(this.getWorkerNodeKey(t)).ready=e.ready,null!=this.emitter&&this.ready&&this.emitter.emit(c.ready,this.info)}handleTaskExecutionResponse(e){const t=this.promiseResponseMap.get(e.id);if(null!=t){null!=e.taskError?(null!=this.emitter&&this.emitter.emit(c.taskError,e.taskError),t.reject(e.taskError.message)):t.resolve(e.data),this.afterTaskExecutionHook(t.worker,e),this.promiseResponseMap.delete(e.id);const s=this.getWorkerNodeKey(t.worker);!0===this.opts.enableTasksQueue&&this.tasksQueueSize(s)>0&&this.executeTask(s,this.dequeueTask(s)),this.workerChoiceStrategyContext.update(s)}}checkAndEmitEvents(){null!=this.emitter&&(this.busy&&this.emitter.emit(c.busy,this.info),this.type===h.dynamic&&this.full&&this.emitter.emit(c.full,this.info))}getWorkerInfo(e){return this.workerNodes[e].info}pushWorkerNode(e){return this.workerNodes.push(new M(e,this.worker))}removeWorkerNode(e){const t=this.getWorkerNodeKey(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategyContext.remove(t))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(this.workerNodes[e].worker,t)}enqueueTask(e,t){return this.workerNodes[e].enqueueTask(t)}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)}setWorkerStatistics(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate},workerId:this.getWorkerInfo(this.getWorkerNodeKey(e)).id})}}class A extends P{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}setupHook(){t.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return t.isPrimary}destroyWorker(e){this.sendToWorker(e,{kill:!0,workerId:e.id}),e.on("disconnect",(()=>{e.kill()})),e.disconnect()}sendToWorker(e,t){e.send(t)}createWorker(){return t.fork(this.opts.env)}get type(){return h.fixed}get worker(){return q.cluster}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}class Q extends P{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}isMain(){return o.isMainThread}async destroyWorker(e){this.sendToWorker(e,{kill:!0,workerId:e.threadId}),await e.terminate()}sendToWorker(e,t){e.postMessage(t)}createWorker(){return new o.Worker(this.filePath,{env:o.SHARE_ENV,...this.opts.workerOptions})}get type(){return h.fixed}get worker(){return q.thread}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}const U=6e4,D=f.SOFT;class F extends a.AsyncResource{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;aliveInterval;constructor(e,t,s,r,i={killBehavior:D,maxInactiveTime:U}){super(e),this.isMain=t,this.mainWorker=r,this.opts=i,this.checkWorkerOptions(this.opts),this.checkTaskFunctions(s),this.isMain||this.mainWorker?.on("message",this.messageListener.bind(this))}checkWorkerOptions(e){this.opts.killBehavior=e.killBehavior??D,this.opts.maxInactiveTime=e.maxInactiveTime??U,delete this.opts.async}checkTaskFunctions(e){if(null==e)throw new Error("taskFunctions parameter is mandatory");if(this.taskFunctions=new Map,"function"==typeof e)this.taskFunctions.set(d,e.bind(this));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("function"!=typeof r)throw new TypeError("A taskFunctions parameter object value is not a function");this.taskFunctions.set(s,r.bind(this)),t&&(this.taskFunctions.set(d,r.bind(this)),t=!1)}if(t)throw new Error("taskFunctions parameter object is empty")}}}hasTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");return this.taskFunctions.has(e)}addTaskFunction(e,t){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===d)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{return this.taskFunctions.get(e)===this.taskFunctions.get(d)&&this.taskFunctions.set(d,t.bind(this)),this.taskFunctions.set(e,t.bind(this)),!0}catch{return!1}}removeTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===d)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(d))throw new Error("Cannot remove the task function used as the default task function");return this.taskFunctions.delete(e)}setDefaultTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===d)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(d,this.taskFunctions.get(e)?.bind(this)),!0}catch{return!1}}messageListener(e){e.workerId===this.id&&(null!=e.ready?this.workerReady():null!=e.statistics?this.statistics=e.statistics:null!=e.checkAlive?e.checkAlive?this.startCheckAlive():this.stopCheckAlive():null!=e.id&&null!=e.data?this.run(e):!0===e.kill&&(this.stopCheckAlive(),this.emitDestroy()))}workerReady(){!this.isMain&&this.sendToMainWorker({ready:!0,workerId:this.id})}startCheckAlive(){this.lastTaskTimestamp=r.performance.now(),this.aliveInterval=setInterval(this.checkAlive.bind(this),(this.opts.maxInactiveTime??U)/2),this.checkAlive.bind(this)()}stopCheckAlive(){null!=this.aliveInterval&&clearInterval(this.aliveInterval)}checkAlive(){r.performance.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??U)&&this.sendToMainWorker({kill:this.opts.killBehavior,workerId:this.id})}getMainWorker(){if(null==this.mainWorker)throw new Error("Main worker not set");return this.mainWorker}handleError(e){return e instanceof Error?e.message:e}run(e){const t=this.getTaskFunction(e.name);(e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name)(t)?this.runInAsyncScope(this.runAsync.bind(this),this,t,e):this.runInAsyncScope(this.runSync.bind(this),this,t,e)}runSync(e,t){try{let s=this.beginTaskPerformance(t.name);const r=e(t.data);s=this.endTaskPerformance(s),this.sendToMainWorker({data:r,taskPerformance:s,workerId:this.id,id:t.id})}catch(e){const s=this.handleError(e);this.sendToMainWorker({taskError:{name:t.name??d,message:s,data:t.data},workerId:this.id,id:t.id})}finally{this.isMain||null==this.aliveInterval||(this.lastTaskTimestamp=r.performance.now())}}runAsync(e,t){let s=this.beginTaskPerformance(t.name);e(t.data).then((e=>(s=this.endTaskPerformance(s),this.sendToMainWorker({data:e,taskPerformance:s,workerId:this.id,id:t.id}),null))).catch((e=>{const s=this.handleError(e);this.sendToMainWorker({taskError:{name:t.name??d,message:s,data:t.data},workerId:this.id,id:t.id})})).finally((()=>{this.isMain||null==this.aliveInterval||(this.lastTaskTimestamp=r.performance.now())})).catch(m)}getTaskFunction(e){e=e??d;const t=this.taskFunctions.get(e);if(null==t)throw new Error(`Task function '${e}' not found`);return t}beginTaskPerformance(e){return this.checkStatistics(),{name:e??d,timestamp:r.performance.now(),...this.statistics.elu&&{elu:r.performance.eventLoopUtilization()}}}endTaskPerformance(e){return this.checkStatistics(),{...e,...this.statistics.runTime&&{runTime:r.performance.now()-e.timestamp},...this.statistics.elu&&{elu:r.performance.eventLoopUtilization(e.elu)}}}checkStatistics(){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set")}}exports.ClusterWorker=class extends F{constructor(e,s={}){super("worker-cluster-pool:poolifier",t.isPrimary,e,t.worker,s)}get id(){return this.getMainWorker().id}sendToMainWorker(e){this.getMainWorker().send(e)}},exports.DynamicClusterPool=class extends A{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return h.dynamic}get maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}},exports.DynamicThreadPool=class extends Q{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return h.dynamic}get maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}},exports.FixedClusterPool=A,exports.FixedThreadPool=Q,exports.KillBehaviors=f,exports.Measurements=W,exports.PoolEvents=c,exports.PoolTypes=h,exports.ThreadWorker=class extends F{constructor(e,t={}){super("worker-thread-pool:poolifier",o.isMainThread,e,o.parentPort,t)}get id(){return o.threadId}sendToMainWorker(e){this.getMainWorker().postMessage(e)}handleError(e){return e}},exports.WorkerChoiceStrategies=y,exports.WorkerTypes=q,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};
|
|
1
|
+
"use strict";var e=require("node:events"),t=require("node:cluster"),r=require("node:crypto"),s=require("node:perf_hooks"),i=require("node:fs"),o=require("node:os"),a=require("node:worker_threads"),n=require("node:async_hooks");function u(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var s=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,s.get?s:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var h=u(o);const k=Object.freeze({fixed:"fixed",dynamic:"dynamic"});class c extends e.EventEmitter{}const d=Object.freeze({full:"full",ready:"ready",busy:"busy",error:"error",taskError:"taskError"}),m="default",l=Object.freeze((()=>{})),g={runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},p={aggregate:!1,average:!1,median:!1},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},y=(e,t=2)=>{const r=Math.pow(10,t);return Math.round(e*r*(1+Number.EPSILON))/r},T=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),f=Object.freeze({SOFT:"SOFT",HARD:"HARD"}),W=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"}),x=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"});class S{pool;opts;nextWorkerNodeKey=0;strategyPolicy={useDynamicWorker:!1};taskStatisticsRequirements={runTime:p,waitTime:p,elu:p};constructor(e,t=g){this.pool=e,this.opts=t,this.choose=this.choose.bind(this)}setTaskStatisticsRequirements(e){this.taskStatisticsRequirements.runTime.average&&!0===e.runTime?.median&&(this.taskStatisticsRequirements.runTime.average=!1,this.taskStatisticsRequirements.runTime.median=e.runTime.median),this.taskStatisticsRequirements.runTime.median&&!1===e.runTime?.median&&(this.taskStatisticsRequirements.runTime.average=!0,this.taskStatisticsRequirements.runTime.median=e.runTime.median),this.taskStatisticsRequirements.waitTime.average&&!0===e.waitTime?.median&&(this.taskStatisticsRequirements.waitTime.average=!1,this.taskStatisticsRequirements.waitTime.median=e.waitTime.median),this.taskStatisticsRequirements.waitTime.median&&!1===e.waitTime?.median&&(this.taskStatisticsRequirements.waitTime.average=!0,this.taskStatisticsRequirements.waitTime.median=e.waitTime.median),this.taskStatisticsRequirements.elu.average&&!0===e.elu?.median&&(this.taskStatisticsRequirements.elu.average=!1,this.taskStatisticsRequirements.elu.median=e.elu.median),this.taskStatisticsRequirements.elu.median&&!1===e.elu?.median&&(this.taskStatisticsRequirements.elu.average=!0,this.taskStatisticsRequirements.elu.median=e.elu.median)}setOptions(e){this.opts=e??g,this.setTaskStatisticsRequirements(this.opts)}isWorkerNodeReady(e){return this.pool.workerNodes[e].info.ready}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}computeDefaultWorkerWeight(){let e=0;for(const t of o.cpus()){const r=t.speed.toString().length-1;e+=1/(t.speed/Math.pow(10,r))*Math.pow(10,r)}return Math.round(e/o.cpus().length)}}class N extends S{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:p,elu:{aggregate:!0,average:!0,median:!1}};workersVirtualTaskEndTimestamp=[];constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.workersVirtualTaskEndTimestamp=[],!0}update(e){return this.computeWorkerVirtualTaskEndTimestamp(e),!0}choose(){return this.fairShareNextWorkerNodeKey()}remove(e){return this.workersVirtualTaskEndTimestamp.splice(e,1),!0}fairShareNextWorkerNodeKey(){let e=1/0;for(const[t]of this.pool.workerNodes.entries()){null==this.workersVirtualTaskEndTimestamp[t]&&this.computeWorkerVirtualTaskEndTimestamp(t);const r=this.workersVirtualTaskEndTimestamp[t];this.isWorkerNodeReady(t)&&r<e&&(e=r,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}computeWorkerVirtualTaskEndTimestamp(e){this.workersVirtualTaskEndTimestamp[e]=this.getWorkerVirtualTaskEndTimestamp(e,this.getWorkerVirtualTaskStartTimestamp(e))}getWorkerVirtualTaskEndTimestamp(e,t){return t+(this.opts.measurement===x.elu?this.getWorkerTaskElu(e):this.getWorkerTaskRunTime(e))}getWorkerVirtualTaskStartTimestamp(e){return Math.max(performance.now(),this.workersVirtualTaskEndTimestamp[e]??-1/0)}}class v extends S{strategyPolicy={useDynamicWorker:!0};roundId=0;roundWeights;defaultWorkerWeight;constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight(),this.roundWeights=this.getRoundWeights()}reset(){return this.nextWorkerNodeKey=0,this.roundId=0,!0}update(){return!0}choose(){let e,t;for(let r=this.roundId;r<this.roundWeights.length;r++)for(let s=this.nextWorkerNodeKey;s<this.pool.workerNodes.length;s++){const i=this.opts.weights?.[s]??this.defaultWorkerWeight;if(this.isWorkerNodeReady(s)&&i>=this.roundWeights[r]){e=r,t=s;break}}this.roundId=e??0,this.nextWorkerNodeKey=t??0;const r=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+1,r}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 R extends S{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:p};constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.leastBusyNextWorkerNodeKey()}remove(){return!0}leastBusyNextWorkerNodeKey(){let e=1/0;for(const[t,r]of this.pool.workerNodes.entries()){const s=(r.usage.runTime?.aggregate??0)+(r.usage.waitTime?.aggregate??0);if(this.isWorkerNodeReady(t)&&0===s){this.nextWorkerNodeKey=t;break}this.isWorkerNodeReady(t)&&s<e&&(e=s,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}}class E extends S{constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.leastUsedNextWorkerNodeKey()}remove(){return!0}leastUsedNextWorkerNodeKey(){let e=1/0;for(const[t,r]of this.pool.workerNodes.entries()){const s=r.usage.tasks,i=s.executed+s.executing+s.queued;if(this.isWorkerNodeReady(t)&&0===i){this.nextWorkerNodeKey=t;break}this.isWorkerNodeReady(t)&&i<e&&(e=i,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}}class b extends S{taskStatisticsRequirements={runTime:p,waitTime:p,elu:{aggregate:!0,average:!1,median:!1}};constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.leastEluNextWorkerNodeKey()}remove(){return!0}leastEluNextWorkerNodeKey(){let e=1/0;for(const[t,r]of this.pool.workerNodes.entries()){const s=r.usage,i=s.elu?.active?.aggregate??0;if(this.isWorkerNodeReady(t)&&0===i){this.nextWorkerNodeKey=t;break}this.isWorkerNodeReady(t)&&i<e&&(e=i,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}}class C extends S{strategyPolicy={useDynamicWorker:!0};constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.nextWorkerNodeKey=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;do{this.roundRobinNextWorkerNodeKey()}while(!this.isWorkerNodeReady(this.nextWorkerNodeKey));return 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+1,this.nextWorkerNodeKey}}class I extends S{strategyPolicy={useDynamicWorker:!0};taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:p,elu:p};defaultWorkerWeight;workerVirtualTaskRunTime=0;constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight()}reset(){return this.nextWorkerNodeKey=0,this.workerVirtualTaskRunTime=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;do{this.weightedRoundRobinNextWorkerNodeKey()}while(!this.isWorkerNodeReady(this.nextWorkerNodeKey));return 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.defaultWorkerWeight)?this.workerVirtualTaskRunTime=e+this.getWorkerTaskRunTime(this.nextWorkerNodeKey):(this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:this.nextWorkerNodeKey+1,this.workerVirtualTaskRunTime=0),this.nextWorkerNodeKey}}class O{workerChoiceStrategy;workerChoiceStrategies;constructor(e,t=W.ROUND_ROBIN,r=g){this.workerChoiceStrategy=t,this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[W.ROUND_ROBIN,new(C.bind(this))(e,r)],[W.LEAST_USED,new(E.bind(this))(e,r)],[W.LEAST_BUSY,new(R.bind(this))(e,r)],[W.LEAST_ELU,new(b.bind(this))(e,r)],[W.FAIR_SHARE,new(N.bind(this))(e,r)],[W.WEIGHTED_ROUND_ROBIN,new(I.bind(this))(e,r)],[W.INTERLEAVED_WEIGHTED_ROUND_ROBIN,new(v.bind(this))(e,r)]])}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)throw new Error("Worker node key chosen is null or undefined");return e}remove(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).remove(e)}setOptions(e){for(const t of this.workerChoiceStrategies.values())t.setOptions(e)}}class q 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,...r){let s;return arguments.length>=3&&void 0!==t?(s=super.splice(e,t),this.push(...r)):s=2===arguments.length?super.splice(e,t):super.splice(e),s}resize(e){if(this.checkSize(e),0===e)this.length=0;else if(e<this.size)for(let t=e;t<this.size;t++)super.pop();this.size=e}empty(){return 0===this.length}full(){return this.length===this.size}checkSize(e){if(!Number.isSafeInteger(e))throw new TypeError(`Invalid circular array size: ${e} is not a safe integer`);if(e<0)throw new RangeError(`Invalid circular array size: ${e} < 0`)}}class z{items;offset;size;maxSize;constructor(){this.clear()}enqueue(e){return this.items.push(e),++this.size,this.size>this.maxSize&&(this.maxSize=this.size),this.size}dequeue(){if(this.size<=0)return;const e=this.items[this.offset];return 2*++this.offset>=this.items.length&&(this.items=this.items.slice(this.offset),this.offset=0),--this.size,e}peek(){if(!(this.size<=0))return this.items[this.offset]}clear(){this.items=[],this.offset=0,this.size=0,this.maxSize=0}[Symbol.iterator](){const e=this.items;let t=this.offset;return{next:()=>{if(t>=e.length)return{value:void 0,done:!0};const r=e[t];return++t,{value:r,done:!1}}}}}const K=Object.freeze({cluster:"cluster",thread:"thread"});class P{worker;info;usage;tasksUsage;tasksQueue;constructor(e,t){this.worker=e,this.info=this.initWorkerInfo(e,t),this.usage=this.initWorkerUsage(),this.tasksUsage=new Map,this.tasksQueue=new z}tasksQueueSize(){return this.tasksQueue.size}tasksQueueMaxSize(){return this.tasksQueue.maxSize}enqueueTask(e){return this.tasksQueue.enqueue(e)}dequeueTask(){return this.tasksQueue.dequeue()}clearTasksQueue(){this.tasksQueue.clear()}resetUsage(){this.usage=this.initWorkerUsage(),this.tasksUsage.clear()}getTaskWorkerUsage(e){return this.tasksUsage.has(e)||this.tasksUsage.set(e,this.initTaskWorkerUsage(e)),this.tasksUsage.get(e)}initWorkerInfo(e,t){return{id:this.getWorkerId(e,t),type:t,dynamic:!1,ready:!1}}initWorkerUsage(){const e=()=>this.tasksQueueSize(),t=()=>this.tasksQueueMaxSize();return{tasks:{executed:0,executing:0,get queued(){return e()},get maxQueued(){return t()},failed:0},runTime:{history:new q},waitTime:{history:new q},elu:{idle:{history:new q},active:{history:new q}}}}initTaskWorkerUsage(e){const t=()=>{let t=0;for(const r of this.tasksQueue)r.name===e&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},failed:0},runTime:{history:new q},waitTime:{history:new q},elu:{idle:{history:new q},active:{history:new q}}}}getWorkerId(e,t){return t===K.thread?e.threadId:t===K.cluster?e.id:void 0}}class M{numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;startTimestamp;constructor(e,t,r){if(this.numberOfWorkers=e,this.filePath=t,this.opts=r,!this.isMain())throw new Error("Cannot start a pool from a worker!");for(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),this.checkAndEmitEvents=this.checkAndEmitEvents.bind(this),!0===this.opts.enableEvents&&(this.emitter=new c),this.workerChoiceStrategyContext=new O(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook();this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.numberOfWorkers;)this.createAndSetupWorker();this.startTimestamp=s.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(!i.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(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 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??W.ROUND_ROBIN,this.checkValidWorkerChoiceStrategy(this.opts.workerChoiceStrategy),this.opts.workerChoiceStrategyOptions=e.workerChoiceStrategyOptions??g,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(W).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.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(x).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 tasks concurrency: must be an integer");if(null!=e?.concurrency&&e.concurrency<=0)throw new Error(`Invalid worker tasks concurrency '${e.concurrency}'`)}get info(){return{version:"2.6.15",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:y(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),queuedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.queued),0),maxQueuedTasks:this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.maxQueued??0)),0),failedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.failed),0),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&{runTime:{minimum:y(Math.min(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:y(Math.max(...this.workerNodes.map((e=>e.usage.runTime?.maximum??-1/0)))),average:y(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)/this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.executed??0)),0)),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&{median:y(w(this.workerNodes.map((e=>e.usage.runTime?.median??0))))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:y(Math.min(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:y(Math.max(...this.workerNodes.map((e=>e.usage.waitTime?.maximum??-1/0)))),average:y(this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0)/this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.executed??0)),0)),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&{median:y(w(this.workerNodes.map((e=>e.usage.waitTime?.median??0))))}}}}}get starting(){return this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.minSize}get ready(){return this.workerNodes.reduce(((e,t)=>!t.info.dynamic&&t.info.ready?e+1:e),0)>=this.minSize}get utilization(){const e=(s.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}getWorkerById(e){return this.workerNodes.find((t=>t.info.id===e))?.worker}checkMessageWorkerId(e){if(null!=e.workerId&&null==this.getWorkerById(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKey(e){return this.workerNodes.findIndex((t=>t.worker===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 of this.workerNodes)e.resetUsage(),this.setWorkerStatistics(e.worker)}setWorkerChoiceStrategyOptions(e){this.checkValidWorkerChoiceStrategyOptions(e),this.opts.workerChoiceStrategyOptions=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)):null!=this.opts.tasksQueueOptions&&delete this.opts.tasksQueueOptions}buildTasksQueueOptions(e){return{concurrency:e?.concurrency??1}}get full(){return this.workerNodes.length>=this.maxSize}internalBusy(){return-1===this.workerNodes.findIndex((e=>0===e.usage.tasks.executing))}async execute(e,t){const i=s.performance.now(),o=this.chooseWorkerNode(),a={name:t??m,data:e??{},timestamp:i,workerId:this.getWorkerInfo(o).id,id:r.randomUUID()},n=new Promise(((e,t)=>{this.promiseResponseMap.set(a.id,{resolve:e,reject:t,worker:this.workerNodes[o].worker})}));return!0===this.opts.enableTasksQueue&&(this.busy||this.workerNodes[o].usage.tasks.executing>=this.opts.tasksQueueOptions.concurrency)?this.enqueueTask(o,a):this.executeTask(o,a),this.checkAndEmitEvents(),n}async destroy(){await Promise.all(this.workerNodes.map((async(e,t)=>{this.flushTasksQueue(t);const r=new Promise((t=>{e.worker.on("exit",(()=>{t()}))}));await this.destroyWorker(e.worker),await r})))}setupHook(){}beforeTaskExecutionHook(e,t){const r=this.workerNodes[e].usage;++r.tasks.executing,this.updateWaitTimeWorkerUsage(r,t);const s=this.workerNodes[e].getTaskWorkerUsage(t.name);++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t)}afterTaskExecutionHook(e,t){const r=this.getWorkerNodeKey(e),s=this.workerNodes[r].usage;this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t);const i=this.workerNodes[r].getTaskWorkerUsage(t.taskPerformance?.name??m);this.updateTaskStatisticsWorkerUsage(i,t),this.updateRunTimeWorkerUsage(i,t),this.updateEluWorkerUsage(i,t)}updateTaskStatisticsWorkerUsage(e,t){const r=e.tasks;--r.executing,null==t.taskError?++r.executed:++r.failed}updateRunTimeWorkerUsage(e,t){if(this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate){const r=t.taskPerformance?.runTime??0;e.runTime.aggregate=(e.runTime.aggregate??0)+r,e.runTime.minimum=Math.min(r,e.runTime?.minimum??1/0),e.runTime.maximum=Math.max(r,e.runTime?.maximum??-1/0),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.average&&0!==e.tasks.executed&&(e.runTime.average=e.runTime.aggregate/e.tasks.executed),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&null!=t.taskPerformance?.runTime&&(e.runTime.history.push(t.taskPerformance.runTime),e.runTime.median=w(e.runTime.history))}}updateWaitTimeWorkerUsage(e,t){const r=s.performance.now(),i=r-(t.timestamp??r);this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&(e.waitTime.aggregate=(e.waitTime?.aggregate??0)+i,e.waitTime.minimum=Math.min(i,e.waitTime?.minimum??1/0),e.waitTime.maximum=Math.max(i,e.waitTime?.maximum??-1/0),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.average&&0!==e.tasks.executed&&(e.waitTime.average=e.waitTime.aggregate/e.tasks.executed),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&(e.waitTime.history.push(i),e.waitTime.median=w(e.waitTime.history)))}updateEluWorkerUsage(e,t){this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate&&null!=t.taskPerformance?.elu&&(e.elu.idle.aggregate=(e.elu.idle?.aggregate??0)+t.taskPerformance.elu.idle,e.elu.active.aggregate=(e.elu.active?.aggregate??0)+t.taskPerformance.elu.active,null!=e.elu.utilization?e.elu.utilization=(e.elu.utilization+t.taskPerformance.elu.utilization)/2:e.elu.utilization=t.taskPerformance.elu.utilization,e.elu.idle.minimum=Math.min(t.taskPerformance.elu.idle,e.elu.idle?.minimum??1/0),e.elu.idle.maximum=Math.max(t.taskPerformance.elu.idle,e.elu.idle?.maximum??-1/0),e.elu.active.minimum=Math.min(t.taskPerformance.elu.active,e.elu.active?.minimum??1/0),e.elu.active.maximum=Math.max(t.taskPerformance.elu.active,e.elu.active?.maximum??-1/0),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.average&&0!==e.tasks.executed&&(e.elu.idle.average=e.elu.idle.aggregate/e.tasks.executed,e.elu.active.average=e.elu.active.aggregate/e.tasks.executed),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.median&&(e.elu.idle.history.push(t.taskPerformance.elu.idle),e.elu.active.history.push(t.taskPerformance.elu.active),e.elu.idle.median=w(e.elu.idle.history),e.elu.active.median=w(e.elu.active.history)))}chooseWorkerNode(){if(this.shallCreateDynamicWorker()){const e=this.createAndSetupDynamicWorker();if(this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker)return this.getWorkerNodeKey(e)}return this.workerChoiceStrategyContext.execute()}shallCreateDynamicWorker(){return this.type===k.dynamic&&!this.full&&this.internalBusy()}createAndSetupWorker(){const e=this.createWorker();return e.on("message",this.opts.messageHandler??l),e.on("error",this.opts.errorHandler??l),e.on("error",(t=>{const r=this.getWorkerNodeKey(e),s=this.getWorkerInfo(r);s.ready=!1,null!=this.emitter&&this.emitter.emit(d.error,t),!0!==this.opts.restartWorkerOnError||this.starting||(s.dynamic?this.createAndSetupDynamicWorker():this.createAndSetupWorker()),!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(r)})),e.on("online",this.opts.onlineHandler??l),e.on("exit",this.opts.exitHandler??l),e.once("exit",(()=>{this.removeWorkerNode(e)})),this.addWorkerNode(e),this.afterWorkerSetup(e),e}createAndSetupDynamicWorker(){const e=this.createAndSetupWorker();this.registerWorkerMessageListener(e,(t=>{const r=this.getWorkerNodeKey(e);var s;s=f.HARD,(t.kill===s||null!=t.kill&&(!1===this.opts.enableTasksQueue&&0===this.workerNodes[r].usage.tasks.executing||!0===this.opts.enableTasksQueue&&0===this.workerNodes[r].usage.tasks.executing&&0===this.tasksQueueSize(r)))&&this.destroyWorker(e)}));const t=this.getWorkerInfo(this.getWorkerNodeKey(e));return t.dynamic=!0,this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker&&(t.ready=!0),this.sendToWorker(e,{checkActive:!0,workerId:t.id}),e}registerWorkerMessageListener(e,t){e.on("message",t)}afterWorkerSetup(e){this.registerWorkerMessageListener(e,this.workerListener()),this.sendWorkerStartupMessage(e),this.setWorkerStatistics(e)}sendWorkerStartupMessage(e){this.sendToWorker(e,{ready:!1,workerId:this.getWorkerInfo(this.getWorkerNodeKey(e)).id})}redistributeQueuedTasks(e){for(;this.tasksQueueSize(e)>0;){let t=e,r=1/0;for(const[s,i]of this.workerNodes.entries()){const o=this.getWorkerInfo(s);if(s!==e&&o.ready&&0===i.usage.tasks.queued){t=s;break}s!==e&&o.ready&&i.usage.tasks.queued<r&&(r=i.usage.tasks.queued,t=s)}this.enqueueTask(t,this.dequeueTask(e))}}workerListener(){return e=>{this.checkMessageWorkerId(e),null!=e.ready?this.handleWorkerReadyResponse(e):null!=e.id&&this.handleTaskExecutionResponse(e)}}handleWorkerReadyResponse(e){const t=this.getWorkerById(e.workerId);this.getWorkerInfo(this.getWorkerNodeKey(t)).ready=e.ready,null!=this.emitter&&this.ready&&this.emitter.emit(d.ready,this.info)}handleTaskExecutionResponse(e){const t=this.promiseResponseMap.get(e.id);if(null!=t){null!=e.taskError?(null!=this.emitter&&this.emitter.emit(d.taskError,e.taskError),t.reject(e.taskError.message)):t.resolve(e.data),this.afterTaskExecutionHook(t.worker,e),this.promiseResponseMap.delete(e.id);const r=this.getWorkerNodeKey(t.worker);!0===this.opts.enableTasksQueue&&this.tasksQueueSize(r)>0&&this.executeTask(r,this.dequeueTask(r)),this.workerChoiceStrategyContext.update(r)}}checkAndEmitEvents(){null!=this.emitter&&(this.busy&&this.emitter.emit(d.busy,this.info),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 P(e,this.worker);return this.starting&&(t.info.ready=!0),this.workerNodes.push(t)}removeWorkerNode(e){const t=this.getWorkerNodeKey(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategyContext.remove(t))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(this.workerNodes[e].worker,t)}enqueueTask(e,t){return this.workerNodes[e].enqueueTask(t)}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)}setWorkerStatistics(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate},workerId:this.getWorkerInfo(this.getWorkerNodeKey(e)).id})}}class A extends M{opts;constructor(e,t,r={}){super(e,t,r),this.opts=r}setupHook(){t.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return t.isPrimary}destroyWorker(e){this.sendToWorker(e,{kill:!0,workerId:e.id}),e.on("disconnect",(()=>{e.kill()})),e.disconnect()}sendToWorker(e,t){e.send(t)}createWorker(){return t.fork(this.opts.env)}get type(){return k.fixed}get worker(){return K.cluster}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}class Q extends M{opts;constructor(e,t,r={}){super(e,t,r),this.opts=r}isMain(){return a.isMainThread}async destroyWorker(e){this.sendToWorker(e,{kill:!0,workerId:e.threadId}),await e.terminate()}sendToWorker(e,t){e.postMessage(t)}createWorker(){return new a.Worker(this.filePath,{env:a.SHARE_ENV,...this.opts.workerOptions})}get type(){return k.fixed}get worker(){return K.thread}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}const U=6e4,D=f.SOFT;class F extends n.AsyncResource{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,r,s,i={killBehavior:D,maxInactiveTime:U}){super(e),this.isMain=t,this.mainWorker=s,this.opts=i,this.checkWorkerOptions(this.opts),this.checkTaskFunctions(r),this.isMain||this.mainWorker?.on("message",this.messageListener.bind(this))}checkWorkerOptions(e){this.opts.killBehavior=e.killBehavior??D,this.opts.maxInactiveTime=e.maxInactiveTime??U,delete this.opts.async}checkTaskFunctions(e){if(null==e)throw new Error("taskFunctions parameter is mandatory");if(this.taskFunctions=new Map,"function"==typeof e)this.taskFunctions.set(m,e.bind(this));else{if(!T(e))throw new TypeError("taskFunctions parameter is not a function or a plain object");{let t=!0;for(const[r,s]of Object.entries(e)){if("string"!=typeof r)throw new TypeError("A taskFunctions parameter object key is not a string");if("function"!=typeof s)throw new TypeError("A taskFunctions parameter object value is not a function");this.taskFunctions.set(r,s.bind(this)),t&&(this.taskFunctions.set(m,s.bind(this)),t=!1)}if(t)throw new Error("taskFunctions parameter object is empty")}}}hasTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");return this.taskFunctions.has(e)}addTaskFunction(e,t){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===m)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{return this.taskFunctions.get(e)===this.taskFunctions.get(m)&&this.taskFunctions.set(m,t.bind(this)),this.taskFunctions.set(e,t.bind(this)),!0}catch{return!1}}removeTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===m)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(m))throw new Error("Cannot remove the task function used as the default task function");return this.taskFunctions.delete(e)}setDefaultTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===m)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(m,this.taskFunctions.get(e)?.bind(this)),!0}catch{return!1}}messageListener(e){e.workerId===this.id&&(null!=e.ready?this.sendReadyResponse():null!=e.statistics?this.statistics=e.statistics:null!=e.checkActive?e.checkActive?this.startCheckActive():this.stopCheckActive():null!=e.id&&null!=e.data?this.run(e):!0===e.kill&&(this.stopCheckActive(),this.emitDestroy()))}sendReadyResponse(){!this.isMain&&this.sendToMainWorker({ready:!0,workerId:this.id})}startCheckActive(){this.lastTaskTimestamp=s.performance.now(),this.activeInterval=setInterval(this.checkActive.bind(this),(this.opts.maxInactiveTime??U)/2)}stopCheckActive(){null!=this.activeInterval&&clearInterval(this.activeInterval)}checkActive(){s.performance.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??U)&&this.sendToMainWorker({kill:this.opts.killBehavior,workerId:this.id})}getMainWorker(){if(null==this.mainWorker)throw new Error("Main worker not set");return this.mainWorker}handleError(e){return e instanceof Error?e.message:e}run(e){const t=this.getTaskFunction(e.name);(e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name)(t)?this.runInAsyncScope(this.runAsync.bind(this),this,t,e):this.runInAsyncScope(this.runSync.bind(this),this,t,e)}runSync(e,t){try{let r=this.beginTaskPerformance(t.name);const s=e(t.data);r=this.endTaskPerformance(r),this.sendToMainWorker({data:s,taskPerformance:r,workerId:this.id,id:t.id})}catch(e){const r=this.handleError(e);this.sendToMainWorker({taskError:{name:t.name??m,message:r,data:t.data},workerId:this.id,id:t.id})}finally{this.isMain||null==this.activeInterval||(this.lastTaskTimestamp=s.performance.now())}}runAsync(e,t){let r=this.beginTaskPerformance(t.name);e(t.data).then((e=>(r=this.endTaskPerformance(r),this.sendToMainWorker({data:e,taskPerformance:r,workerId:this.id,id:t.id}),null))).catch((e=>{const r=this.handleError(e);this.sendToMainWorker({taskError:{name:t.name??m,message:r,data:t.data},workerId:this.id,id:t.id})})).finally((()=>{this.isMain||null==this.activeInterval||(this.lastTaskTimestamp=s.performance.now())})).catch(l)}getTaskFunction(e){e=e??m;const t=this.taskFunctions.get(e);if(null==t)throw new Error(`Task function '${e}' not found`);return t}beginTaskPerformance(e){return this.checkStatistics(),{name:e??m,timestamp:s.performance.now(),...this.statistics.elu&&{elu:s.performance.eventLoopUtilization()}}}endTaskPerformance(e){return this.checkStatistics(),{...e,...this.statistics.runTime&&{runTime:s.performance.now()-e.timestamp},...this.statistics.elu&&{elu:s.performance.eventLoopUtilization(e.elu)}}}checkStatistics(){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set")}}exports.ClusterWorker=class extends F{constructor(e,r={}){super("worker-cluster-pool:poolifier",t.isPrimary,e,t.worker,r)}get id(){return this.getMainWorker().id}sendToMainWorker(e){this.getMainWorker().send(e)}},exports.DynamicClusterPool=class extends A{max;constructor(e,t,r,s={}){super(e,r,s),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return k.dynamic}get maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}},exports.DynamicThreadPool=class extends Q{max;constructor(e,t,r,s={}){super(e,r,s),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return k.dynamic}get maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}},exports.FixedClusterPool=A,exports.FixedThreadPool=Q,exports.KillBehaviors=f,exports.Measurements=x,exports.PoolEvents=d,exports.PoolTypes=k,exports.ThreadWorker=class extends F{constructor(e,t={}){super("worker-thread-pool:poolifier",a.isMainThread,e,a.parentPort,t)}get id(){return a.threadId}sendToMainWorker(e){this.getMainWorker().postMessage(e)}handleError(e){return e}},exports.WorkerChoiceStrategies=W,exports.WorkerTypes=K,exports.availableParallelism=()=>{let e=1;try{e=h.availableParallelism()}catch{const t=h.cpus();Array.isArray(t)&&t.length>0&&(e=t.length)}return e};
|
package/lib/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{EventEmitter as e}from"node:events";import t from"node:cluster";import{randomUUID as s}from"node:crypto";import{performance as r}from"node:perf_hooks";import*as i from"node:os";import{cpus as o}from"node:os";import{isMainThread as a,Worker as n,SHARE_ENV as h,parentPort as u,threadId as k}from"node:worker_threads";import{AsyncResource as c}from"node:async_hooks";const d=Object.freeze({fixed:"fixed",dynamic:"dynamic"});class m extends e{}const l=Object.freeze({full:"full",ready:"ready",busy:"busy",error:"error",taskError:"taskError"}),g="default",w=Object.freeze((()=>{})),p={runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},T={aggregate:!1,average:!1,median:!1},f=()=>{let e=1;try{e=i.availableParallelism()}catch{const t=i.cpus();Array.isArray(t)&&t.length>0&&(e=t.length)}return e},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},W=(e,t=2)=>{const s=Math.pow(10,t);return Math.round(e*s*(1+Number.EPSILON))/s},S=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),x=Object.freeze({SOFT:"SOFT",HARD:"HARD"}),N=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"}),v=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"});class I{pool;opts;nextWorkerNodeId=0;strategyPolicy={useDynamicWorker:!1};taskStatisticsRequirements={runTime:T,waitTime:T,elu:T};constructor(e,t=p){this.pool=e,this.opts=t,this.choose=this.choose.bind(this)}setTaskStatisticsRequirements(e){this.taskStatisticsRequirements.runTime.average&&!0===e.runTime?.median&&(this.taskStatisticsRequirements.runTime.average=!1,this.taskStatisticsRequirements.runTime.median=e.runTime.median),this.taskStatisticsRequirements.runTime.median&&!1===e.runTime?.median&&(this.taskStatisticsRequirements.runTime.average=!0,this.taskStatisticsRequirements.runTime.median=e.runTime.median),this.taskStatisticsRequirements.waitTime.average&&!0===e.waitTime?.median&&(this.taskStatisticsRequirements.waitTime.average=!1,this.taskStatisticsRequirements.waitTime.median=e.waitTime.median),this.taskStatisticsRequirements.waitTime.median&&!1===e.waitTime?.median&&(this.taskStatisticsRequirements.waitTime.average=!0,this.taskStatisticsRequirements.waitTime.median=e.waitTime.median),this.taskStatisticsRequirements.elu.average&&!0===e.elu?.median&&(this.taskStatisticsRequirements.elu.average=!1,this.taskStatisticsRequirements.elu.median=e.elu.median),this.taskStatisticsRequirements.elu.median&&!1===e.elu?.median&&(this.taskStatisticsRequirements.elu.average=!0,this.taskStatisticsRequirements.elu.median=e.elu.median)}setOptions(e){this.opts=e??p,this.setTaskStatisticsRequirements(this.opts)}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}computeDefaultWorkerWeight(){let e=0;for(const t of o()){const s=t.speed.toString().length-1;e+=1/(t.speed/Math.pow(10,s))*Math.pow(10,s)}return Math.round(e/o().length)}}class E extends I{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:T,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(){let e=1/0;for(const[t]of this.pool.workerNodes.entries()){null==this.workersVirtualTaskEndTimestamp[t]&&this.computeWorkerVirtualTaskEndTimestamp(t);const s=this.workersVirtualTaskEndTimestamp[t];s<e&&(e=s,this.nextWorkerNodeId=t)}return this.nextWorkerNodeId}remove(e){return this.workersVirtualTaskEndTimestamp.splice(e,1),!0}computeWorkerVirtualTaskEndTimestamp(e){this.workersVirtualTaskEndTimestamp[e]=this.getWorkerVirtualTaskEndTimestamp(e,this.getWorkerVirtualTaskStartTimestamp(e))}getWorkerVirtualTaskEndTimestamp(e,t){return t+(this.opts.measurement===v.elu?this.getWorkerTaskElu(e):this.getWorkerTaskRunTime(e))}getWorkerVirtualTaskStartTimestamp(e){return Math.max(performance.now(),this.workersVirtualTaskEndTimestamp[e]??-1/0)}}class R extends I{strategyPolicy={useDynamicWorker:!0};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.nextWorkerNodeId=0,this.roundId=0,!0}update(){return!0}choose(){let e,t;for(let s=this.roundId;s<this.roundWeights.length;s++)for(let r=this.nextWorkerNodeId;r<this.pool.workerNodes.length;r++){if((this.opts.weights?.[r]??this.defaultWorkerWeight)>=this.roundWeights[s]){e=s,t=r;break}}this.roundId=e??0,this.nextWorkerNodeId=t??0;const s=this.nextWorkerNodeId;return this.nextWorkerNodeId===this.pool.workerNodes.length-1?(this.nextWorkerNodeId=0,this.roundId=this.roundId===this.roundWeights.length-1?0:this.roundId+1):this.nextWorkerNodeId=this.nextWorkerNodeId+1,s}remove(e){return this.nextWorkerNodeId===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeId=0:this.nextWorkerNodeId>this.pool.workerNodes.length-1&&(this.nextWorkerNodeId=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 I{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:T};constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=(s.usage.runTime?.aggregate??0)+(s.usage.waitTime?.aggregate??0);if(0===r){this.nextWorkerNodeId=t;break}r<e&&(e=r,this.nextWorkerNodeId=t)}return this.nextWorkerNodeId}remove(){return!0}}class C extends I{constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=s.usage.tasks,i=r.executed+r.executing+r.queued;if(0===i){this.nextWorkerNodeId=t;break}i<e&&(e=i,this.nextWorkerNodeId=t)}return this.nextWorkerNodeId}remove(){return!0}}class O extends I{taskStatisticsRequirements={runTime:T,waitTime:T,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(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=s.usage,i=r.elu?.active?.aggregate??0;if(0===i){this.nextWorkerNodeId=t;break}i<e&&(e=i,this.nextWorkerNodeId=t)}return this.nextWorkerNodeId}remove(){return!0}}class z extends I{strategyPolicy={useDynamicWorker:!0};constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.nextWorkerNodeId=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeId;return this.nextWorkerNodeId=this.nextWorkerNodeId===this.pool.workerNodes.length-1?0:this.nextWorkerNodeId+1,e}remove(e){return this.nextWorkerNodeId===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeId=0:this.nextWorkerNodeId>this.pool.workerNodes.length-1&&(this.nextWorkerNodeId=this.pool.workerNodes.length-1)),!0}}class q extends I{strategyPolicy={useDynamicWorker:!0};taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:T,elu:T};defaultWorkerWeight;workerVirtualTaskRunTime=0;constructor(e,t=p){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight()}reset(){return this.nextWorkerNodeId=0,this.workerVirtualTaskRunTime=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeId,t=this.workerVirtualTaskRunTime;return t<(this.opts.weights?.[e]??this.defaultWorkerWeight)?this.workerVirtualTaskRunTime=t+this.getWorkerTaskRunTime(e):(this.nextWorkerNodeId=this.nextWorkerNodeId===this.pool.workerNodes.length-1?0:this.nextWorkerNodeId+1,this.workerVirtualTaskRunTime=0),e}remove(e){return this.nextWorkerNodeId===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeId=0:this.nextWorkerNodeId>this.pool.workerNodes.length-1&&(this.nextWorkerNodeId=this.pool.workerNodes.length-1),this.workerVirtualTaskRunTime=0),!0}}class M{workerChoiceStrategy;workerChoiceStrategies;constructor(e,t=N.ROUND_ROBIN,s=p){this.workerChoiceStrategy=t,this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[N.ROUND_ROBIN,new(z.bind(this))(e,s)],[N.LEAST_USED,new(C.bind(this))(e,s)],[N.LEAST_BUSY,new(b.bind(this))(e,s)],[N.LEAST_ELU,new(O.bind(this))(e,s)],[N.FAIR_SHARE,new(E.bind(this))(e,s)],[N.WEIGHTED_ROUND_ROBIN,new(q.bind(this))(e,s)],[N.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)throw new Error("Worker node key chosen is null or undefined");return e}remove(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).remove(e)}setOptions(e){for(const t of this.workerChoiceStrategies.values())t.setOptions(e)}}class A 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;return arguments.length>=3&&void 0!==t?(r=super.splice(e,t),this.push(...s)):r=2===arguments.length?super.splice(e,t):super.splice(e),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{items;offset;size;maxSize;constructor(){this.clear()}enqueue(e){return this.items.push(e),++this.size,this.size>this.maxSize&&(this.maxSize=this.size),this.size}dequeue(){if(this.size<=0)return;const e=this.items[this.offset];return 2*++this.offset>=this.items.length&&(this.items=this.items.slice(this.offset),this.offset=0),--this.size,e}peek(){if(!(this.size<=0))return this.items[this.offset]}clear(){this.items=[],this.offset=0,this.size=0,this.maxSize=0}[Symbol.iterator](){const e=this.items;let t=this.offset;return{next:()=>{if(t>=e.length)return{value:void 0,done:!0};const s=e[t];return++t,{value:s,done:!1}}}}}const P=Object.freeze({cluster:"cluster",thread:"thread"});class U{worker;info;usage;tasksUsage;tasksQueue;constructor(e,t){this.worker=e,this.info=this.initWorkerInfo(e,t),this.usage=this.initWorkerUsage(),this.tasksUsage=new Map,this.tasksQueue=new Q}tasksQueueSize(){return this.tasksQueue.size}tasksQueueMaxSize(){return this.tasksQueue.maxSize}enqueueTask(e){return this.tasksQueue.enqueue(e)}dequeueTask(){return this.tasksQueue.dequeue()}clearTasksQueue(){this.tasksQueue.clear()}resetUsage(){this.usage=this.initWorkerUsage(),this.tasksUsage.clear()}getTaskWorkerUsage(e){return this.tasksUsage.has(e)||this.tasksUsage.set(e,this.initTaskWorkerUsage(e)),this.tasksUsage.get(e)}initWorkerInfo(e,t){return{id:this.getWorkerId(e,t),type:t,dynamic:!1,ready:!1}}initWorkerUsage(){const e=()=>this.tasksQueueSize(),t=()=>this.tasksQueueMaxSize();return{tasks:{executed:0,executing:0,get queued(){return e()},get maxQueued(){return t()},failed:0},runTime:{history:new A},waitTime:{history:new A},elu:{idle:{history:new A},active:{history:new A}}}}initTaskWorkerUsage(e){const t=()=>{let t=0;for(const s of this.tasksQueue)s.name===e&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},failed:0},runTime:{history:new A},waitTime:{history:new A},elu:{idle:{history:new A},active:{history:new A}}}}getWorkerId(e,t){return t===P.thread?e.threadId:t===P.cluster?e.id:void 0}}class D{numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;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!");for(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),this.checkAndEmitEvents=this.checkAndEmitEvents.bind(this),!0===this.opts.enableEvents&&(this.emitter=new m),this.workerChoiceStrategyContext=new M(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook();this.workerNodes.length<this.numberOfWorkers;)this.createAndSetupWorker();this.startTimestamp=r.now()}checkFilePath(e){if(null==e||"string"==typeof e&&0===e.trim().length)throw new Error("Please specify a file with a worker implementation")}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===d.fixed&&0===e)throw new RangeError("Cannot instantiate a fixed pool with zero worker")}checkDynamicPoolSize(e,t){if(this.type===d.dynamic){if(e>t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size");if(0===e&&0===t)throw new RangeError("Cannot instantiate a dynamic pool with a minimum pool size and a maximum pool size equal to zero");if(e===t)throw new RangeError("Cannot instantiate a dynamic pool with a minimum pool size equal to the maximum pool size. Use a fixed pool instead")}}checkPoolOptions(e){if(!S(e))throw new TypeError("Invalid pool options: must be a plain object");this.opts.workerChoiceStrategy=e.workerChoiceStrategy??N.ROUND_ROBIN,this.checkValidWorkerChoiceStrategy(this.opts.workerChoiceStrategy),this.opts.workerChoiceStrategyOptions=e.workerChoiceStrategyOptions??p,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(N).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)}checkValidWorkerChoiceStrategyOptions(e){if(!S(e))throw new TypeError("Invalid worker choice strategy options: must be a plain object");if(null!=e.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(v).includes(e.measurement))throw new Error(`Invalid worker choice strategy options: invalid measurement '${e.measurement}'`)}checkValidTasksQueueOptions(e){if(null!=e&&!S(e))throw new TypeError("Invalid tasks queue options: must be a plain object");if(null!=e?.concurrency&&!Number.isSafeInteger(e.concurrency))throw new TypeError("Invalid worker tasks concurrency: must be an integer");if(null!=e?.concurrency&&e.concurrency<=0)throw new Error(`Invalid worker tasks concurrency '${e.concurrency}'`)}get info(){return{version:"2.6.14",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:W(this.utilization)},workerNodes:this.workerNodes.length,idleWorkerNodes:this.workerNodes.reduce(((e,t)=>0===t.usage.tasks.executing?e+1:e),0),busyWorkerNodes:this.workerNodes.reduce(((e,t)=>t.usage.tasks.executing>0?e+1:e),0),executedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executed),0),executingTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executing),0),queuedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.queued),0),maxQueuedTasks:this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.maxQueued??0)),0),failedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.failed),0),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&{runTime:{minimum:W(Math.min(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:W(Math.max(...this.workerNodes.map((e=>e.usage.runTime?.maximum??-1/0)))),average:W(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)/this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.executed??0)),0)),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&{median:W(y(this.workerNodes.map((e=>e.usage.runTime?.median??0))))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:W(Math.min(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:W(Math.max(...this.workerNodes.map((e=>e.usage.waitTime?.maximum??-1/0)))),average:W(this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0)/this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.executed??0)),0)),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&{median:W(y(this.workerNodes.map((e=>e.usage.waitTime?.median??0))))}}}}}get starting(){return this.workerNodes.length<this.minSize||this.workerNodes.length>=this.minSize&&this.workerNodes.some((e=>!e.info.ready))}get ready(){return this.workerNodes.length>=this.minSize&&this.workerNodes.every((e=>e.info.ready))}get utilization(){const e=(r.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}getWorkerById(e){return this.workerNodes.find((t=>t.info.id===e))?.worker}checkMessageWorkerId(e){if(null!=e.workerId&&null==this.getWorkerById(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKey(e){return this.workerNodes.findIndex((t=>t.worker===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 of this.workerNodes)e.resetUsage(),this.setWorkerStatistics(e.worker)}setWorkerChoiceStrategyOptions(e){this.checkValidWorkerChoiceStrategyOptions(e),this.opts.workerChoiceStrategyOptions=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)):null!=this.opts.tasksQueueOptions&&delete this.opts.tasksQueueOptions}buildTasksQueueOptions(e){return{concurrency:e?.concurrency??1}}get full(){return this.workerNodes.length>=this.maxSize}internalBusy(){return-1===this.workerNodes.findIndex((e=>0===e.usage.tasks.executing))}async execute(e,t){const i=r.now(),o=this.chooseWorkerNode(),a={name:t??g,data:e??{},timestamp:i,workerId:this.getWorkerInfo(o).id,id:s()},n=new Promise(((e,t)=>{this.promiseResponseMap.set(a.id,{resolve:e,reject:t,worker:this.workerNodes[o].worker})}));return!0===this.opts.enableTasksQueue&&(this.busy||this.workerNodes[o].usage.tasks.executing>=this.opts.tasksQueueOptions.concurrency)?this.enqueueTask(o,a):this.executeTask(o,a),this.checkAndEmitEvents(),n}async destroy(){await Promise.all(this.workerNodes.map((async(e,t)=>{this.flushTasksQueue(t);const s=new Promise((t=>{e.worker.on("exit",(()=>{t()}))}));await this.destroyWorker(e.worker),await s})))}setupHook(){}beforeTaskExecutionHook(e,t){const s=this.workerNodes[e].usage;++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t);const r=this.workerNodes[e].getTaskWorkerUsage(t.name);++r.tasks.executing,this.updateWaitTimeWorkerUsage(r,t)}afterTaskExecutionHook(e,t){const s=this.getWorkerNodeKey(e),r=this.workerNodes[s].usage;this.updateTaskStatisticsWorkerUsage(r,t),this.updateRunTimeWorkerUsage(r,t),this.updateEluWorkerUsage(r,t);const i=this.workerNodes[s].getTaskWorkerUsage(t.taskPerformance?.name??g);this.updateTaskStatisticsWorkerUsage(i,t),this.updateRunTimeWorkerUsage(i,t),this.updateEluWorkerUsage(i,t)}updateTaskStatisticsWorkerUsage(e,t){const s=e.tasks;--s.executing,null==t.taskError?++s.executed:++s.failed}updateRunTimeWorkerUsage(e,t){if(this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate){const s=t.taskPerformance?.runTime??0;e.runTime.aggregate=(e.runTime.aggregate??0)+s,e.runTime.minimum=Math.min(s,e.runTime?.minimum??1/0),e.runTime.maximum=Math.max(s,e.runTime?.maximum??-1/0),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.average&&0!==e.tasks.executed&&(e.runTime.average=e.runTime.aggregate/e.tasks.executed),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&null!=t.taskPerformance?.runTime&&(e.runTime.history.push(t.taskPerformance.runTime),e.runTime.median=y(e.runTime.history))}}updateWaitTimeWorkerUsage(e,t){const s=r.now(),i=s-(t.timestamp??s);this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&(e.waitTime.aggregate=(e.waitTime?.aggregate??0)+i,e.waitTime.minimum=Math.min(i,e.waitTime?.minimum??1/0),e.waitTime.maximum=Math.max(i,e.waitTime?.maximum??-1/0),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.average&&0!==e.tasks.executed&&(e.waitTime.average=e.waitTime.aggregate/e.tasks.executed),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&(e.waitTime.history.push(i),e.waitTime.median=y(e.waitTime.history)))}updateEluWorkerUsage(e,t){this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate&&null!=t.taskPerformance?.elu&&(e.elu.idle.aggregate=(e.elu.idle?.aggregate??0)+t.taskPerformance.elu.idle,e.elu.active.aggregate=(e.elu.active?.aggregate??0)+t.taskPerformance.elu.active,null!=e.elu.utilization?e.elu.utilization=(e.elu.utilization+t.taskPerformance.elu.utilization)/2:e.elu.utilization=t.taskPerformance.elu.utilization,e.elu.idle.minimum=Math.min(t.taskPerformance.elu.idle,e.elu.idle?.minimum??1/0),e.elu.idle.maximum=Math.max(t.taskPerformance.elu.idle,e.elu.idle?.maximum??-1/0),e.elu.active.minimum=Math.min(t.taskPerformance.elu.active,e.elu.active?.minimum??1/0),e.elu.active.maximum=Math.max(t.taskPerformance.elu.active,e.elu.active?.maximum??-1/0),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.average&&0!==e.tasks.executed&&(e.elu.idle.average=e.elu.idle.aggregate/e.tasks.executed,e.elu.active.average=e.elu.active.aggregate/e.tasks.executed),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.median&&(e.elu.idle.history.push(t.taskPerformance.elu.idle),e.elu.active.history.push(t.taskPerformance.elu.active),e.elu.idle.median=y(e.elu.idle.history),e.elu.active.median=y(e.elu.active.history)))}chooseWorkerNode(){if(this.shallCreateDynamicWorker()){const e=this.createAndSetupDynamicWorker();if(this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker)return this.getWorkerNodeKey(e)}return this.workerChoiceStrategyContext.execute()}shallCreateDynamicWorker(){return this.type===d.dynamic&&!this.full&&this.internalBusy()}registerWorkerMessageListener(e,t){e.on("message",t)}afterWorkerSetup(e){this.registerWorkerMessageListener(e,this.workerListener()),this.sendToWorker(e,{ready:!1,workerId:this.getWorkerInfo(this.getWorkerNodeKey(e)).id}),this.setWorkerStatistics(e)}createAndSetupWorker(){const e=this.createWorker();return e.on("message",this.opts.messageHandler??w),e.on("error",this.opts.errorHandler??w),e.on("error",(t=>{null!=this.emitter&&this.emitter.emit(l.error,t),!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(e),!0!==this.opts.restartWorkerOnError||this.starting||(this.getWorkerInfo(this.getWorkerNodeKey(e)).dynamic?this.createAndSetupDynamicWorker():this.createAndSetupWorker())})),e.on("online",this.opts.onlineHandler??w),e.on("exit",this.opts.exitHandler??w),e.once("exit",(()=>{this.removeWorkerNode(e)})),this.pushWorkerNode(e),this.afterWorkerSetup(e),e}redistributeQueuedTasks(e){const t=this.getWorkerNodeKey(e);for(;this.tasksQueueSize(t)>0;){let e=t,s=1/0;for(const[r,i]of this.workerNodes.entries()){if(r!==t&&0===i.usage.tasks.queued){e=r;break}r!==t&&i.usage.tasks.queued<s&&(s=i.usage.tasks.queued,e=r)}this.enqueueTask(e,this.dequeueTask(t))}}createAndSetupDynamicWorker(){const e=this.createAndSetupWorker();this.registerWorkerMessageListener(e,(t=>{const s=this.getWorkerNodeKey(e);var r;r=x.HARD,(t.kill===r||null!=t.kill&&(!1===this.opts.enableTasksQueue&&0===this.workerNodes[s].usage.tasks.executing||!0===this.opts.enableTasksQueue&&0===this.workerNodes[s].usage.tasks.executing&&0===this.tasksQueueSize(s)))&&this.destroyWorker(e)}));const t=this.getWorkerInfo(this.getWorkerNodeKey(e));return t.dynamic=!0,this.sendToWorker(e,{checkAlive:!0,workerId:t.id}),e}workerListener(){return e=>{this.checkMessageWorkerId(e),null!=e.ready&&null!=e.workerId?this.handleWorkerReadyMessage(e):null!=e.id&&this.handleTaskExecutionResponse(e)}}handleWorkerReadyMessage(e){const t=this.getWorkerById(e.workerId);this.getWorkerInfo(this.getWorkerNodeKey(t)).ready=e.ready,null!=this.emitter&&this.ready&&this.emitter.emit(l.ready,this.info)}handleTaskExecutionResponse(e){const t=this.promiseResponseMap.get(e.id);if(null!=t){null!=e.taskError?(null!=this.emitter&&this.emitter.emit(l.taskError,e.taskError),t.reject(e.taskError.message)):t.resolve(e.data),this.afterTaskExecutionHook(t.worker,e),this.promiseResponseMap.delete(e.id);const s=this.getWorkerNodeKey(t.worker);!0===this.opts.enableTasksQueue&&this.tasksQueueSize(s)>0&&this.executeTask(s,this.dequeueTask(s)),this.workerChoiceStrategyContext.update(s)}}checkAndEmitEvents(){null!=this.emitter&&(this.busy&&this.emitter.emit(l.busy,this.info),this.type===d.dynamic&&this.full&&this.emitter.emit(l.full,this.info))}getWorkerInfo(e){return this.workerNodes[e].info}pushWorkerNode(e){return this.workerNodes.push(new U(e,this.worker))}removeWorkerNode(e){const t=this.getWorkerNodeKey(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategyContext.remove(t))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(this.workerNodes[e].worker,t)}enqueueTask(e,t){return this.workerNodes[e].enqueueTask(t)}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)}setWorkerStatistics(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate},workerId:this.getWorkerInfo(this.getWorkerNodeKey(e)).id})}}class F extends D{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}setupHook(){t.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return t.isPrimary}destroyWorker(e){this.sendToWorker(e,{kill:!0,workerId:e.id}),e.on("disconnect",(()=>{e.kill()})),e.disconnect()}sendToWorker(e,t){e.send(t)}createWorker(){return t.fork(this.opts.env)}get type(){return d.fixed}get worker(){return P.cluster}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}class _ extends F{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return d.dynamic}get maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}}class V extends D{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}isMain(){return a}async destroyWorker(e){this.sendToWorker(e,{kill:!0,workerId:e.threadId}),await e.terminate()}sendToWorker(e,t){e.postMessage(t)}createWorker(){return new n(this.filePath,{env:h,...this.opts.workerOptions})}get type(){return d.fixed}get worker(){return P.thread}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}class B extends V{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return d.dynamic}get maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}}const j=6e4,L=x.SOFT;class H extends c{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;aliveInterval;constructor(e,t,s,r,i={killBehavior:L,maxInactiveTime:j}){super(e),this.isMain=t,this.mainWorker=r,this.opts=i,this.checkWorkerOptions(this.opts),this.checkTaskFunctions(s),this.isMain||this.mainWorker?.on("message",this.messageListener.bind(this))}checkWorkerOptions(e){this.opts.killBehavior=e.killBehavior??L,this.opts.maxInactiveTime=e.maxInactiveTime??j,delete this.opts.async}checkTaskFunctions(e){if(null==e)throw new Error("taskFunctions parameter is mandatory");if(this.taskFunctions=new Map,"function"==typeof e)this.taskFunctions.set(g,e.bind(this));else{if(!S(e))throw new TypeError("taskFunctions parameter is not a function or a plain object");{let t=!0;for(const[s,r]of Object.entries(e)){if("string"!=typeof s)throw new TypeError("A taskFunctions parameter object key is not a string");if("function"!=typeof r)throw new TypeError("A taskFunctions parameter object value is not a function");this.taskFunctions.set(s,r.bind(this)),t&&(this.taskFunctions.set(g,r.bind(this)),t=!1)}if(t)throw new Error("taskFunctions parameter object is empty")}}}hasTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");return this.taskFunctions.has(e)}addTaskFunction(e,t){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(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{return this.taskFunctions.get(e)===this.taskFunctions.get(g)&&this.taskFunctions.set(g,t.bind(this)),this.taskFunctions.set(e,t.bind(this)),!0}catch{return!1}}removeTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(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");return this.taskFunctions.delete(e)}setDefaultTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(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)?.bind(this)),!0}catch{return!1}}messageListener(e){e.workerId===this.id&&(null!=e.ready?this.workerReady():null!=e.statistics?this.statistics=e.statistics:null!=e.checkAlive?e.checkAlive?this.startCheckAlive():this.stopCheckAlive():null!=e.id&&null!=e.data?this.run(e):!0===e.kill&&(this.stopCheckAlive(),this.emitDestroy()))}workerReady(){!this.isMain&&this.sendToMainWorker({ready:!0,workerId:this.id})}startCheckAlive(){this.lastTaskTimestamp=r.now(),this.aliveInterval=setInterval(this.checkAlive.bind(this),(this.opts.maxInactiveTime??j)/2),this.checkAlive.bind(this)()}stopCheckAlive(){null!=this.aliveInterval&&clearInterval(this.aliveInterval)}checkAlive(){r.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??j)&&this.sendToMainWorker({kill:this.opts.killBehavior,workerId:this.id})}getMainWorker(){if(null==this.mainWorker)throw new Error("Main worker not set");return this.mainWorker}handleError(e){return e instanceof Error?e.message:e}run(e){const t=this.getTaskFunction(e.name);(e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name)(t)?this.runInAsyncScope(this.runAsync.bind(this),this,t,e):this.runInAsyncScope(this.runSync.bind(this),this,t,e)}runSync(e,t){try{let s=this.beginTaskPerformance(t.name);const r=e(t.data);s=this.endTaskPerformance(s),this.sendToMainWorker({data:r,taskPerformance:s,workerId:this.id,id:t.id})}catch(e){const s=this.handleError(e);this.sendToMainWorker({taskError:{name:t.name??g,message:s,data:t.data},workerId:this.id,id:t.id})}finally{this.isMain||null==this.aliveInterval||(this.lastTaskTimestamp=r.now())}}runAsync(e,t){let s=this.beginTaskPerformance(t.name);e(t.data).then((e=>(s=this.endTaskPerformance(s),this.sendToMainWorker({data:e,taskPerformance:s,workerId:this.id,id:t.id}),null))).catch((e=>{const s=this.handleError(e);this.sendToMainWorker({taskError:{name:t.name??g,message:s,data:t.data},workerId:this.id,id:t.id})})).finally((()=>{this.isMain||null==this.aliveInterval||(this.lastTaskTimestamp=r.now())})).catch(w)}getTaskFunction(e){e=e??g;const t=this.taskFunctions.get(e);if(null==t)throw new Error(`Task function '${e}' not found`);return t}beginTaskPerformance(e){return this.checkStatistics(),{name:e??g,timestamp:r.now(),...this.statistics.elu&&{elu:r.eventLoopUtilization()}}}endTaskPerformance(e){return this.checkStatistics(),{...e,...this.statistics.runTime&&{runTime:r.now()-e.timestamp},...this.statistics.elu&&{elu:r.eventLoopUtilization(e.elu)}}}checkStatistics(){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set")}}class K extends H{constructor(e,s={}){super("worker-cluster-pool:poolifier",t.isPrimary,e,t.worker,s)}get id(){return this.getMainWorker().id}sendToMainWorker(e){this.getMainWorker().send(e)}}class $ extends H{constructor(e,t={}){super("worker-thread-pool:poolifier",a,e,u,t)}get id(){return k}sendToMainWorker(e){this.getMainWorker().postMessage(e)}handleError(e){return e}}export{K as ClusterWorker,_ as DynamicClusterPool,B as DynamicThreadPool,F as FixedClusterPool,V as FixedThreadPool,x as KillBehaviors,v as Measurements,l as PoolEvents,d as PoolTypes,$ as ThreadWorker,N as WorkerChoiceStrategies,P as WorkerTypes,f as availableParallelism};
|
|
1
|
+
import{EventEmitter as e}from"node:events";import t from"node:cluster";import{randomUUID as s}from"node:crypto";import{performance as r}from"node:perf_hooks";import{existsSync as i}from"node:fs";import*as o from"node:os";import{cpus as a}from"node:os";import{isMainThread as n,Worker as h,SHARE_ENV as u,parentPort as k,threadId as c}from"node:worker_threads";import{AsyncResource as d}from"node:async_hooks";const m=Object.freeze({fixed:"fixed",dynamic:"dynamic"});class l extends e{}const g=Object.freeze({full:"full",ready:"ready",busy:"busy",error:"error",taskError:"taskError"}),w="default",p=Object.freeze((()=>{})),y={runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},T={aggregate:!1,average:!1,median:!1},f=()=>{let e=1;try{e=o.availableParallelism()}catch{const t=o.cpus();Array.isArray(t)&&t.length>0&&(e=t.length)}return e},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},S=(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),N=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"}),R=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"});class E{pool;opts;nextWorkerNodeKey=0;strategyPolicy={useDynamicWorker:!1};taskStatisticsRequirements={runTime:T,waitTime:T,elu:T};constructor(e,t=y){this.pool=e,this.opts=t,this.choose=this.choose.bind(this)}setTaskStatisticsRequirements(e){this.taskStatisticsRequirements.runTime.average&&!0===e.runTime?.median&&(this.taskStatisticsRequirements.runTime.average=!1,this.taskStatisticsRequirements.runTime.median=e.runTime.median),this.taskStatisticsRequirements.runTime.median&&!1===e.runTime?.median&&(this.taskStatisticsRequirements.runTime.average=!0,this.taskStatisticsRequirements.runTime.median=e.runTime.median),this.taskStatisticsRequirements.waitTime.average&&!0===e.waitTime?.median&&(this.taskStatisticsRequirements.waitTime.average=!1,this.taskStatisticsRequirements.waitTime.median=e.waitTime.median),this.taskStatisticsRequirements.waitTime.median&&!1===e.waitTime?.median&&(this.taskStatisticsRequirements.waitTime.average=!0,this.taskStatisticsRequirements.waitTime.median=e.waitTime.median),this.taskStatisticsRequirements.elu.average&&!0===e.elu?.median&&(this.taskStatisticsRequirements.elu.average=!1,this.taskStatisticsRequirements.elu.median=e.elu.median),this.taskStatisticsRequirements.elu.median&&!1===e.elu?.median&&(this.taskStatisticsRequirements.elu.average=!0,this.taskStatisticsRequirements.elu.median=e.elu.median)}setOptions(e){this.opts=e??y,this.setTaskStatisticsRequirements(this.opts)}isWorkerNodeReady(e){return this.pool.workerNodes[e].info.ready}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}computeDefaultWorkerWeight(){let e=0;for(const t of a()){const s=t.speed.toString().length-1;e+=1/(t.speed/Math.pow(10,s))*Math.pow(10,s)}return Math.round(e/a().length)}}class b extends E{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:T,elu:{aggregate:!0,average:!0,median:!1}};workersVirtualTaskEndTimestamp=[];constructor(e,t=y){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.workersVirtualTaskEndTimestamp=[],!0}update(e){return this.computeWorkerVirtualTaskEndTimestamp(e),!0}choose(){return this.fairShareNextWorkerNodeKey()}remove(e){return this.workersVirtualTaskEndTimestamp.splice(e,1),!0}fairShareNextWorkerNodeKey(){let e=1/0;for(const[t]of this.pool.workerNodes.entries()){null==this.workersVirtualTaskEndTimestamp[t]&&this.computeWorkerVirtualTaskEndTimestamp(t);const s=this.workersVirtualTaskEndTimestamp[t];this.isWorkerNodeReady(t)&&s<e&&(e=s,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}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 C extends E{strategyPolicy={useDynamicWorker:!0};roundId=0;roundWeights;defaultWorkerWeight;constructor(e,t=y){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight(),this.roundWeights=this.getRoundWeights()}reset(){return this.nextWorkerNodeKey=0,this.roundId=0,!0}update(){return!0}choose(){let e,t;for(let s=this.roundId;s<this.roundWeights.length;s++)for(let r=this.nextWorkerNodeKey;r<this.pool.workerNodes.length;r++){const i=this.opts.weights?.[r]??this.defaultWorkerWeight;if(this.isWorkerNodeReady(r)&&i>=this.roundWeights[s]){e=s,t=r;break}}this.roundId=e??0,this.nextWorkerNodeKey=t??0;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+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 I extends E{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:T};constructor(e,t=y){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.leastBusyNextWorkerNodeKey()}remove(){return!0}leastBusyNextWorkerNodeKey(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=(s.usage.runTime?.aggregate??0)+(s.usage.waitTime?.aggregate??0);if(this.isWorkerNodeReady(t)&&0===r){this.nextWorkerNodeKey=t;break}this.isWorkerNodeReady(t)&&r<e&&(e=r,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}}class O extends E{constructor(e,t=y){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.leastUsedNextWorkerNodeKey()}remove(){return!0}leastUsedNextWorkerNodeKey(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=s.usage.tasks,i=r.executed+r.executing+r.queued;if(this.isWorkerNodeReady(t)&&0===i){this.nextWorkerNodeKey=t;break}this.isWorkerNodeReady(t)&&i<e&&(e=i,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}}class z extends E{taskStatisticsRequirements={runTime:T,waitTime:T,elu:{aggregate:!0,average:!1,median:!1}};constructor(e,t=y){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.leastEluNextWorkerNodeKey()}remove(){return!0}leastEluNextWorkerNodeKey(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=s.usage,i=r.elu?.active?.aggregate??0;if(this.isWorkerNodeReady(t)&&0===i){this.nextWorkerNodeKey=t;break}this.isWorkerNodeReady(t)&&i<e&&(e=i,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}}class q extends E{strategyPolicy={useDynamicWorker:!0};constructor(e,t=y){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.nextWorkerNodeKey=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;do{this.roundRobinNextWorkerNodeKey()}while(!this.isWorkerNodeReady(this.nextWorkerNodeKey));return 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+1,this.nextWorkerNodeKey}}class K extends E{strategyPolicy={useDynamicWorker:!0};taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:T,elu:T};defaultWorkerWeight;workerVirtualTaskRunTime=0;constructor(e,t=y){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight()}reset(){return this.nextWorkerNodeKey=0,this.workerVirtualTaskRunTime=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;do{this.weightedRoundRobinNextWorkerNodeKey()}while(!this.isWorkerNodeReady(this.nextWorkerNodeKey));return 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.defaultWorkerWeight)?this.workerVirtualTaskRunTime=e+this.getWorkerTaskRunTime(this.nextWorkerNodeKey):(this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:this.nextWorkerNodeKey+1,this.workerVirtualTaskRunTime=0),this.nextWorkerNodeKey}}class M{workerChoiceStrategy;workerChoiceStrategies;constructor(e,t=v.ROUND_ROBIN,s=y){this.workerChoiceStrategy=t,this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[v.ROUND_ROBIN,new(q.bind(this))(e,s)],[v.LEAST_USED,new(O.bind(this))(e,s)],[v.LEAST_BUSY,new(I.bind(this))(e,s)],[v.LEAST_ELU,new(z.bind(this))(e,s)],[v.FAIR_SHARE,new(b.bind(this))(e,s)],[v.WEIGHTED_ROUND_ROBIN,new(K.bind(this))(e,s)],[v.INTERLEAVED_WEIGHTED_ROUND_ROBIN,new(C.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)throw new Error("Worker node key chosen is null or undefined");return e}remove(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).remove(e)}setOptions(e){for(const t of this.workerChoiceStrategies.values())t.setOptions(e)}}class Q 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;return arguments.length>=3&&void 0!==t?(r=super.splice(e,t),this.push(...s)):r=2===arguments.length?super.splice(e,t):super.splice(e),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 A{items;offset;size;maxSize;constructor(){this.clear()}enqueue(e){return this.items.push(e),++this.size,this.size>this.maxSize&&(this.maxSize=this.size),this.size}dequeue(){if(this.size<=0)return;const e=this.items[this.offset];return 2*++this.offset>=this.items.length&&(this.items=this.items.slice(this.offset),this.offset=0),--this.size,e}peek(){if(!(this.size<=0))return this.items[this.offset]}clear(){this.items=[],this.offset=0,this.size=0,this.maxSize=0}[Symbol.iterator](){const e=this.items;let t=this.offset;return{next:()=>{if(t>=e.length)return{value:void 0,done:!0};const s=e[t];return++t,{value:s,done:!1}}}}}const P=Object.freeze({cluster:"cluster",thread:"thread"});class U{worker;info;usage;tasksUsage;tasksQueue;constructor(e,t){this.worker=e,this.info=this.initWorkerInfo(e,t),this.usage=this.initWorkerUsage(),this.tasksUsage=new Map,this.tasksQueue=new A}tasksQueueSize(){return this.tasksQueue.size}tasksQueueMaxSize(){return this.tasksQueue.maxSize}enqueueTask(e){return this.tasksQueue.enqueue(e)}dequeueTask(){return this.tasksQueue.dequeue()}clearTasksQueue(){this.tasksQueue.clear()}resetUsage(){this.usage=this.initWorkerUsage(),this.tasksUsage.clear()}getTaskWorkerUsage(e){return this.tasksUsage.has(e)||this.tasksUsage.set(e,this.initTaskWorkerUsage(e)),this.tasksUsage.get(e)}initWorkerInfo(e,t){return{id:this.getWorkerId(e,t),type:t,dynamic:!1,ready:!1}}initWorkerUsage(){const e=()=>this.tasksQueueSize(),t=()=>this.tasksQueueMaxSize();return{tasks:{executed:0,executing:0,get queued(){return e()},get maxQueued(){return t()},failed:0},runTime:{history:new Q},waitTime:{history:new Q},elu:{idle:{history:new Q},active:{history:new Q}}}}initTaskWorkerUsage(e){const t=()=>{let t=0;for(const s of this.tasksQueue)s.name===e&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},failed:0},runTime:{history:new Q},waitTime:{history:new Q},elu:{idle:{history:new Q},active:{history:new Q}}}}getWorkerId(e,t){return t===P.thread?e.threadId:t===P.cluster?e.id:void 0}}class D{numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;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!");for(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),this.checkAndEmitEvents=this.checkAndEmitEvents.bind(this),!0===this.opts.enableEvents&&(this.emitter=new l),this.workerChoiceStrategyContext=new M(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook();this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.numberOfWorkers;)this.createAndSetupWorker();this.startTimestamp=r.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(!i(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(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 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??v.ROUND_ROBIN,this.checkValidWorkerChoiceStrategy(this.opts.workerChoiceStrategy),this.opts.workerChoiceStrategyOptions=e.workerChoiceStrategyOptions??y,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(!x(e))throw new TypeError("Invalid worker choice strategy options: must be a plain object");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 tasks concurrency: must be an integer");if(null!=e?.concurrency&&e.concurrency<=0)throw new Error(`Invalid worker tasks concurrency '${e.concurrency}'`)}get info(){return{version:"2.6.15",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:S(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),queuedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.queued),0),maxQueuedTasks:this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.maxQueued??0)),0),failedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.failed),0),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&{runTime:{minimum:S(Math.min(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:S(Math.max(...this.workerNodes.map((e=>e.usage.runTime?.maximum??-1/0)))),average:S(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)/this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.executed??0)),0)),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&{median:S(W(this.workerNodes.map((e=>e.usage.runTime?.median??0))))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:S(Math.min(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:S(Math.max(...this.workerNodes.map((e=>e.usage.waitTime?.maximum??-1/0)))),average:S(this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0)/this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.executed??0)),0)),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&{median:S(W(this.workerNodes.map((e=>e.usage.waitTime?.median??0))))}}}}}get starting(){return this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.minSize}get ready(){return this.workerNodes.reduce(((e,t)=>!t.info.dynamic&&t.info.ready?e+1:e),0)>=this.minSize}get utilization(){const e=(r.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}getWorkerById(e){return this.workerNodes.find((t=>t.info.id===e))?.worker}checkMessageWorkerId(e){if(null!=e.workerId&&null==this.getWorkerById(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKey(e){return this.workerNodes.findIndex((t=>t.worker===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 of this.workerNodes)e.resetUsage(),this.setWorkerStatistics(e.worker)}setWorkerChoiceStrategyOptions(e){this.checkValidWorkerChoiceStrategyOptions(e),this.opts.workerChoiceStrategyOptions=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)):null!=this.opts.tasksQueueOptions&&delete this.opts.tasksQueueOptions}buildTasksQueueOptions(e){return{concurrency:e?.concurrency??1}}get full(){return this.workerNodes.length>=this.maxSize}internalBusy(){return-1===this.workerNodes.findIndex((e=>0===e.usage.tasks.executing))}async execute(e,t){const i=r.now(),o=this.chooseWorkerNode(),a={name:t??w,data:e??{},timestamp:i,workerId:this.getWorkerInfo(o).id,id:s()},n=new Promise(((e,t)=>{this.promiseResponseMap.set(a.id,{resolve:e,reject:t,worker:this.workerNodes[o].worker})}));return!0===this.opts.enableTasksQueue&&(this.busy||this.workerNodes[o].usage.tasks.executing>=this.opts.tasksQueueOptions.concurrency)?this.enqueueTask(o,a):this.executeTask(o,a),this.checkAndEmitEvents(),n}async destroy(){await Promise.all(this.workerNodes.map((async(e,t)=>{this.flushTasksQueue(t);const s=new Promise((t=>{e.worker.on("exit",(()=>{t()}))}));await this.destroyWorker(e.worker),await s})))}setupHook(){}beforeTaskExecutionHook(e,t){const s=this.workerNodes[e].usage;++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t);const r=this.workerNodes[e].getTaskWorkerUsage(t.name);++r.tasks.executing,this.updateWaitTimeWorkerUsage(r,t)}afterTaskExecutionHook(e,t){const s=this.getWorkerNodeKey(e),r=this.workerNodes[s].usage;this.updateTaskStatisticsWorkerUsage(r,t),this.updateRunTimeWorkerUsage(r,t),this.updateEluWorkerUsage(r,t);const i=this.workerNodes[s].getTaskWorkerUsage(t.taskPerformance?.name??w);this.updateTaskStatisticsWorkerUsage(i,t),this.updateRunTimeWorkerUsage(i,t),this.updateEluWorkerUsage(i,t)}updateTaskStatisticsWorkerUsage(e,t){const s=e.tasks;--s.executing,null==t.taskError?++s.executed:++s.failed}updateRunTimeWorkerUsage(e,t){if(this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate){const s=t.taskPerformance?.runTime??0;e.runTime.aggregate=(e.runTime.aggregate??0)+s,e.runTime.minimum=Math.min(s,e.runTime?.minimum??1/0),e.runTime.maximum=Math.max(s,e.runTime?.maximum??-1/0),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.average&&0!==e.tasks.executed&&(e.runTime.average=e.runTime.aggregate/e.tasks.executed),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&null!=t.taskPerformance?.runTime&&(e.runTime.history.push(t.taskPerformance.runTime),e.runTime.median=W(e.runTime.history))}}updateWaitTimeWorkerUsage(e,t){const s=r.now(),i=s-(t.timestamp??s);this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&(e.waitTime.aggregate=(e.waitTime?.aggregate??0)+i,e.waitTime.minimum=Math.min(i,e.waitTime?.minimum??1/0),e.waitTime.maximum=Math.max(i,e.waitTime?.maximum??-1/0),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.average&&0!==e.tasks.executed&&(e.waitTime.average=e.waitTime.aggregate/e.tasks.executed),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&(e.waitTime.history.push(i),e.waitTime.median=W(e.waitTime.history)))}updateEluWorkerUsage(e,t){this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate&&null!=t.taskPerformance?.elu&&(e.elu.idle.aggregate=(e.elu.idle?.aggregate??0)+t.taskPerformance.elu.idle,e.elu.active.aggregate=(e.elu.active?.aggregate??0)+t.taskPerformance.elu.active,null!=e.elu.utilization?e.elu.utilization=(e.elu.utilization+t.taskPerformance.elu.utilization)/2:e.elu.utilization=t.taskPerformance.elu.utilization,e.elu.idle.minimum=Math.min(t.taskPerformance.elu.idle,e.elu.idle?.minimum??1/0),e.elu.idle.maximum=Math.max(t.taskPerformance.elu.idle,e.elu.idle?.maximum??-1/0),e.elu.active.minimum=Math.min(t.taskPerformance.elu.active,e.elu.active?.minimum??1/0),e.elu.active.maximum=Math.max(t.taskPerformance.elu.active,e.elu.active?.maximum??-1/0),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.average&&0!==e.tasks.executed&&(e.elu.idle.average=e.elu.idle.aggregate/e.tasks.executed,e.elu.active.average=e.elu.active.aggregate/e.tasks.executed),this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.median&&(e.elu.idle.history.push(t.taskPerformance.elu.idle),e.elu.active.history.push(t.taskPerformance.elu.active),e.elu.idle.median=W(e.elu.idle.history),e.elu.active.median=W(e.elu.active.history)))}chooseWorkerNode(){if(this.shallCreateDynamicWorker()){const e=this.createAndSetupDynamicWorker();if(this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker)return this.getWorkerNodeKey(e)}return this.workerChoiceStrategyContext.execute()}shallCreateDynamicWorker(){return this.type===m.dynamic&&!this.full&&this.internalBusy()}createAndSetupWorker(){const e=this.createWorker();return e.on("message",this.opts.messageHandler??p),e.on("error",this.opts.errorHandler??p),e.on("error",(t=>{const s=this.getWorkerNodeKey(e),r=this.getWorkerInfo(s);r.ready=!1,null!=this.emitter&&this.emitter.emit(g.error,t),!0!==this.opts.restartWorkerOnError||this.starting||(r.dynamic?this.createAndSetupDynamicWorker():this.createAndSetupWorker()),!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(s)})),e.on("online",this.opts.onlineHandler??p),e.on("exit",this.opts.exitHandler??p),e.once("exit",(()=>{this.removeWorkerNode(e)})),this.addWorkerNode(e),this.afterWorkerSetup(e),e}createAndSetupDynamicWorker(){const e=this.createAndSetupWorker();this.registerWorkerMessageListener(e,(t=>{const s=this.getWorkerNodeKey(e);var r;r=N.HARD,(t.kill===r||null!=t.kill&&(!1===this.opts.enableTasksQueue&&0===this.workerNodes[s].usage.tasks.executing||!0===this.opts.enableTasksQueue&&0===this.workerNodes[s].usage.tasks.executing&&0===this.tasksQueueSize(s)))&&this.destroyWorker(e)}));const t=this.getWorkerInfo(this.getWorkerNodeKey(e));return t.dynamic=!0,this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker&&(t.ready=!0),this.sendToWorker(e,{checkActive:!0,workerId:t.id}),e}registerWorkerMessageListener(e,t){e.on("message",t)}afterWorkerSetup(e){this.registerWorkerMessageListener(e,this.workerListener()),this.sendWorkerStartupMessage(e),this.setWorkerStatistics(e)}sendWorkerStartupMessage(e){this.sendToWorker(e,{ready:!1,workerId:this.getWorkerInfo(this.getWorkerNodeKey(e)).id})}redistributeQueuedTasks(e){for(;this.tasksQueueSize(e)>0;){let t=e,s=1/0;for(const[r,i]of this.workerNodes.entries()){const o=this.getWorkerInfo(r);if(r!==e&&o.ready&&0===i.usage.tasks.queued){t=r;break}r!==e&&o.ready&&i.usage.tasks.queued<s&&(s=i.usage.tasks.queued,t=r)}this.enqueueTask(t,this.dequeueTask(e))}}workerListener(){return e=>{this.checkMessageWorkerId(e),null!=e.ready?this.handleWorkerReadyResponse(e):null!=e.id&&this.handleTaskExecutionResponse(e)}}handleWorkerReadyResponse(e){const t=this.getWorkerById(e.workerId);this.getWorkerInfo(this.getWorkerNodeKey(t)).ready=e.ready,null!=this.emitter&&this.ready&&this.emitter.emit(g.ready,this.info)}handleTaskExecutionResponse(e){const t=this.promiseResponseMap.get(e.id);if(null!=t){null!=e.taskError?(null!=this.emitter&&this.emitter.emit(g.taskError,e.taskError),t.reject(e.taskError.message)):t.resolve(e.data),this.afterTaskExecutionHook(t.worker,e),this.promiseResponseMap.delete(e.id);const s=this.getWorkerNodeKey(t.worker);!0===this.opts.enableTasksQueue&&this.tasksQueueSize(s)>0&&this.executeTask(s,this.dequeueTask(s)),this.workerChoiceStrategyContext.update(s)}}checkAndEmitEvents(){null!=this.emitter&&(this.busy&&this.emitter.emit(g.busy,this.info),this.type===m.dynamic&&this.full&&this.emitter.emit(g.full,this.info))}getWorkerInfo(e){return this.workerNodes[e].info}addWorkerNode(e){const t=new U(e,this.worker);return this.starting&&(t.info.ready=!0),this.workerNodes.push(t)}removeWorkerNode(e){const t=this.getWorkerNodeKey(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategyContext.remove(t))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(this.workerNodes[e].worker,t)}enqueueTask(e,t){return this.workerNodes[e].enqueueTask(t)}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)}setWorkerStatistics(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate},workerId:this.getWorkerInfo(this.getWorkerNodeKey(e)).id})}}class F extends D{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}setupHook(){t.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return t.isPrimary}destroyWorker(e){this.sendToWorker(e,{kill:!0,workerId:e.id}),e.on("disconnect",(()=>{e.kill()})),e.disconnect()}sendToWorker(e,t){e.send(t)}createWorker(){return t.fork(this.opts.env)}get type(){return m.fixed}get worker(){return P.cluster}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}class _ extends F{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 maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}}class V extends D{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}isMain(){return n}async destroyWorker(e){this.sendToWorker(e,{kill:!0,workerId:e.threadId}),await e.terminate()}sendToWorker(e,t){e.postMessage(t)}createWorker(){return new h(this.filePath,{env:u,...this.opts.workerOptions})}get type(){return m.fixed}get worker(){return P.thread}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}class B extends V{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 maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}}const j=6e4,L=N.SOFT;class H extends d{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,s,r,i={killBehavior:L,maxInactiveTime:j}){super(e),this.isMain=t,this.mainWorker=r,this.opts=i,this.checkWorkerOptions(this.opts),this.checkTaskFunctions(s),this.isMain||this.mainWorker?.on("message",this.messageListener.bind(this))}checkWorkerOptions(e){this.opts.killBehavior=e.killBehavior??L,this.opts.maxInactiveTime=e.maxInactiveTime??j,delete this.opts.async}checkTaskFunctions(e){if(null==e)throw new Error("taskFunctions parameter is mandatory");if(this.taskFunctions=new Map,"function"==typeof e)this.taskFunctions.set(w,e.bind(this));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)){if("string"!=typeof s)throw new TypeError("A taskFunctions parameter object key is not a string");if("function"!=typeof r)throw new TypeError("A taskFunctions parameter object value is not a function");this.taskFunctions.set(s,r.bind(this)),t&&(this.taskFunctions.set(w,r.bind(this)),t=!1)}if(t)throw new Error("taskFunctions parameter object is empty")}}}hasTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");return this.taskFunctions.has(e)}addTaskFunction(e,t){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===w)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{return this.taskFunctions.get(e)===this.taskFunctions.get(w)&&this.taskFunctions.set(w,t.bind(this)),this.taskFunctions.set(e,t.bind(this)),!0}catch{return!1}}removeTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===w)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(w))throw new Error("Cannot remove the task function used as the default task function");return this.taskFunctions.delete(e)}setDefaultTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===w)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(w,this.taskFunctions.get(e)?.bind(this)),!0}catch{return!1}}messageListener(e){e.workerId===this.id&&(null!=e.ready?this.sendReadyResponse():null!=e.statistics?this.statistics=e.statistics:null!=e.checkActive?e.checkActive?this.startCheckActive():this.stopCheckActive():null!=e.id&&null!=e.data?this.run(e):!0===e.kill&&(this.stopCheckActive(),this.emitDestroy()))}sendReadyResponse(){!this.isMain&&this.sendToMainWorker({ready:!0,workerId:this.id})}startCheckActive(){this.lastTaskTimestamp=r.now(),this.activeInterval=setInterval(this.checkActive.bind(this),(this.opts.maxInactiveTime??j)/2)}stopCheckActive(){null!=this.activeInterval&&clearInterval(this.activeInterval)}checkActive(){r.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??j)&&this.sendToMainWorker({kill:this.opts.killBehavior,workerId:this.id})}getMainWorker(){if(null==this.mainWorker)throw new Error("Main worker not set");return this.mainWorker}handleError(e){return e instanceof Error?e.message:e}run(e){const t=this.getTaskFunction(e.name);(e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name)(t)?this.runInAsyncScope(this.runAsync.bind(this),this,t,e):this.runInAsyncScope(this.runSync.bind(this),this,t,e)}runSync(e,t){try{let s=this.beginTaskPerformance(t.name);const r=e(t.data);s=this.endTaskPerformance(s),this.sendToMainWorker({data:r,taskPerformance:s,workerId:this.id,id:t.id})}catch(e){const s=this.handleError(e);this.sendToMainWorker({taskError:{name:t.name??w,message:s,data:t.data},workerId:this.id,id:t.id})}finally{this.isMain||null==this.activeInterval||(this.lastTaskTimestamp=r.now())}}runAsync(e,t){let s=this.beginTaskPerformance(t.name);e(t.data).then((e=>(s=this.endTaskPerformance(s),this.sendToMainWorker({data:e,taskPerformance:s,workerId:this.id,id:t.id}),null))).catch((e=>{const s=this.handleError(e);this.sendToMainWorker({taskError:{name:t.name??w,message:s,data:t.data},workerId:this.id,id:t.id})})).finally((()=>{this.isMain||null==this.activeInterval||(this.lastTaskTimestamp=r.now())})).catch(p)}getTaskFunction(e){e=e??w;const t=this.taskFunctions.get(e);if(null==t)throw new Error(`Task function '${e}' not found`);return t}beginTaskPerformance(e){return this.checkStatistics(),{name:e??w,timestamp:r.now(),...this.statistics.elu&&{elu:r.eventLoopUtilization()}}}endTaskPerformance(e){return this.checkStatistics(),{...e,...this.statistics.runTime&&{runTime:r.now()-e.timestamp},...this.statistics.elu&&{elu:r.eventLoopUtilization(e.elu)}}}checkStatistics(){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set")}}class $ extends H{constructor(e,s={}){super("worker-cluster-pool:poolifier",t.isPrimary,e,t.worker,s)}get id(){return this.getMainWorker().id}sendToMainWorker(e){this.getMainWorker().send(e)}}class G extends H{constructor(e,t={}){super("worker-thread-pool:poolifier",n,e,k,t)}get id(){return c}sendToMainWorker(e){this.getMainWorker().postMessage(e)}handleError(e){return e}}export{$ as ClusterWorker,_ as DynamicClusterPool,B as DynamicThreadPool,F as FixedClusterPool,V as FixedThreadPool,N as KillBehaviors,R as Measurements,g as PoolEvents,m as PoolTypes,G as ThreadWorker,v as WorkerChoiceStrategies,P as WorkerTypes,f as availableParallelism};
|
|
@@ -85,6 +85,12 @@ export declare abstract class AbstractPool<Worker extends IWorker, Data = unknow
|
|
|
85
85
|
* @returns The worker if found in the pool worker nodes, `undefined` otherwise.
|
|
86
86
|
*/
|
|
87
87
|
private getWorkerById;
|
|
88
|
+
/**
|
|
89
|
+
* Checks if the worker id sent in the received message from a worker is valid.
|
|
90
|
+
*
|
|
91
|
+
* @param message - The received message.
|
|
92
|
+
* @throws {@link https://nodejs.org/api/errors.html#class-error} If the worker id is invalid.
|
|
93
|
+
*/
|
|
88
94
|
private checkMessageWorkerId;
|
|
89
95
|
/**
|
|
90
96
|
* Gets the given worker its worker node key.
|
|
@@ -182,46 +188,47 @@ export declare abstract class AbstractPool<Worker extends IWorker, Data = unknow
|
|
|
182
188
|
* @param message - The message.
|
|
183
189
|
*/
|
|
184
190
|
protected abstract sendToWorker(worker: Worker, message: MessageValue<Data>): void;
|
|
185
|
-
/**
|
|
186
|
-
* Registers a listener callback on the given worker.
|
|
187
|
-
*
|
|
188
|
-
* @param worker - The worker which should register a listener.
|
|
189
|
-
* @param listener - The message listener callback.
|
|
190
|
-
*/
|
|
191
|
-
private registerWorkerMessageListener;
|
|
192
191
|
/**
|
|
193
192
|
* Creates a new worker.
|
|
194
193
|
*
|
|
195
194
|
* @returns Newly created worker.
|
|
196
195
|
*/
|
|
197
196
|
protected abstract createWorker(): Worker;
|
|
198
|
-
/**
|
|
199
|
-
* Function that can be hooked up when a worker has been newly created and moved to the pool worker nodes.
|
|
200
|
-
* Can be overridden.
|
|
201
|
-
*
|
|
202
|
-
* @param worker - The newly created worker.
|
|
203
|
-
*/
|
|
204
|
-
protected afterWorkerSetup(worker: Worker): void;
|
|
205
197
|
/**
|
|
206
198
|
* Creates a new worker and sets it up completely in the pool worker nodes.
|
|
207
199
|
*
|
|
208
200
|
* @returns New, completely set up worker.
|
|
209
201
|
*/
|
|
210
202
|
protected createAndSetupWorker(): Worker;
|
|
211
|
-
private redistributeQueuedTasks;
|
|
212
203
|
/**
|
|
213
204
|
* Creates a new dynamic worker and sets it up completely in the pool worker nodes.
|
|
214
205
|
*
|
|
215
206
|
* @returns New, completely set up dynamic worker.
|
|
216
207
|
*/
|
|
217
208
|
protected createAndSetupDynamicWorker(): Worker;
|
|
209
|
+
/**
|
|
210
|
+
* Registers a listener callback on the given worker.
|
|
211
|
+
*
|
|
212
|
+
* @param worker - The worker which should register a listener.
|
|
213
|
+
* @param listener - The message listener callback.
|
|
214
|
+
*/
|
|
215
|
+
private registerWorkerMessageListener;
|
|
216
|
+
/**
|
|
217
|
+
* Function that can be hooked up when a worker has been newly created and moved to the pool worker nodes.
|
|
218
|
+
* Can be overridden.
|
|
219
|
+
*
|
|
220
|
+
* @param worker - The newly created worker.
|
|
221
|
+
*/
|
|
222
|
+
protected afterWorkerSetup(worker: Worker): void;
|
|
223
|
+
private sendWorkerStartupMessage;
|
|
224
|
+
private redistributeQueuedTasks;
|
|
218
225
|
/**
|
|
219
226
|
* This function is the listener registered for each worker message.
|
|
220
227
|
*
|
|
221
228
|
* @returns The listener function to execute when a message is received from a worker.
|
|
222
229
|
*/
|
|
223
230
|
protected workerListener(): (message: MessageValue<Response>) => void;
|
|
224
|
-
private
|
|
231
|
+
private handleWorkerReadyResponse;
|
|
225
232
|
private handleTaskExecutionResponse;
|
|
226
233
|
private checkAndEmitEvents;
|
|
227
234
|
/**
|
|
@@ -231,18 +238,24 @@ export declare abstract class AbstractPool<Worker extends IWorker, Data = unknow
|
|
|
231
238
|
*/
|
|
232
239
|
private getWorkerInfo;
|
|
233
240
|
/**
|
|
234
|
-
*
|
|
241
|
+
* Adds the given worker in the pool worker nodes.
|
|
235
242
|
*
|
|
236
243
|
* @param worker - The worker.
|
|
237
244
|
* @returns The worker nodes length.
|
|
238
245
|
*/
|
|
239
|
-
private
|
|
246
|
+
private addWorkerNode;
|
|
240
247
|
/**
|
|
241
248
|
* Removes the given worker from the pool worker nodes.
|
|
242
249
|
*
|
|
243
250
|
* @param worker - The worker.
|
|
244
251
|
*/
|
|
245
252
|
private removeWorkerNode;
|
|
253
|
+
/**
|
|
254
|
+
* Executes the given task on the given worker.
|
|
255
|
+
*
|
|
256
|
+
* @param worker - The worker.
|
|
257
|
+
* @param task - The task to execute.
|
|
258
|
+
*/
|
|
246
259
|
private executeTask;
|
|
247
260
|
private enqueueTask;
|
|
248
261
|
private dequeueTask;
|
|
@@ -12,9 +12,9 @@ export declare abstract class AbstractWorkerChoiceStrategy<Worker extends IWorke
|
|
|
12
12
|
protected readonly pool: IPool<Worker, Data, Response>;
|
|
13
13
|
protected opts: WorkerChoiceStrategyOptions;
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* The next worker node key.
|
|
16
16
|
*/
|
|
17
|
-
protected
|
|
17
|
+
protected nextWorkerNodeKey: number;
|
|
18
18
|
/** @inheritDoc */
|
|
19
19
|
readonly strategyPolicy: StrategyPolicy;
|
|
20
20
|
/** @inheritDoc */
|
|
@@ -37,6 +37,7 @@ export declare abstract class AbstractWorkerChoiceStrategy<Worker extends IWorke
|
|
|
37
37
|
abstract remove(workerNodeKey: number): boolean;
|
|
38
38
|
/** @inheritDoc */
|
|
39
39
|
setOptions(opts: WorkerChoiceStrategyOptions): void;
|
|
40
|
+
protected isWorkerNodeReady(workerNodeKey: number): boolean;
|
|
40
41
|
/**
|
|
41
42
|
* Gets the worker task runtime.
|
|
42
43
|
* If the task statistics require the average runtime, the average runtime is returned.
|
|
@@ -27,6 +27,7 @@ export declare class FairShareWorkerChoiceStrategy<Worker extends IWorker, Data
|
|
|
27
27
|
choose(): number;
|
|
28
28
|
/** @inheritDoc */
|
|
29
29
|
remove(workerNodeKey: number): boolean;
|
|
30
|
+
private fairShareNextWorkerNodeKey;
|
|
30
31
|
/**
|
|
31
32
|
* Computes the worker node key virtual task end timestamp.
|
|
32
33
|
*
|
|
@@ -139,7 +139,7 @@ export interface TaskStatisticsRequirements {
|
|
|
139
139
|
*/
|
|
140
140
|
export interface StrategyPolicy {
|
|
141
141
|
/**
|
|
142
|
-
* Expects direct usage of dynamic worker.
|
|
142
|
+
* Expects direct usage of the newly created dynamic worker.
|
|
143
143
|
*/
|
|
144
144
|
readonly useDynamicWorker: boolean;
|
|
145
145
|
}
|
package/lib/pools/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "2.6.
|
|
1
|
+
export declare const version = "2.6.15";
|
package/lib/pools/worker.d.ts
CHANGED
|
@@ -213,7 +213,7 @@ export interface IWorkerNode<Worker extends IWorker, Data = unknown> {
|
|
|
213
213
|
*/
|
|
214
214
|
readonly resetUsage: () => void;
|
|
215
215
|
/**
|
|
216
|
-
* Gets task usage statistics.
|
|
216
|
+
* Gets task worker usage statistics.
|
|
217
217
|
*/
|
|
218
218
|
readonly getTaskWorkerUsage: (name: string) => WorkerUsage | undefined;
|
|
219
219
|
}
|
package/lib/utility-types.d.ts
CHANGED
|
@@ -110,9 +110,9 @@ export interface MessageValue<Data = unknown, ErrorData = unknown> extends Task<
|
|
|
110
110
|
*/
|
|
111
111
|
readonly ready?: boolean;
|
|
112
112
|
/**
|
|
113
|
-
* Whether the worker starts or stops its
|
|
113
|
+
* Whether the worker starts or stops its activity check.
|
|
114
114
|
*/
|
|
115
|
-
readonly
|
|
115
|
+
readonly checkActive?: boolean;
|
|
116
116
|
}
|
|
117
117
|
/**
|
|
118
118
|
* An object holding the execution response promise resolve/reject callbacks.
|
|
@@ -125,11 +125,11 @@ export interface PromiseResponseWrapper<Worker extends IWorker, Response = unkno
|
|
|
125
125
|
/**
|
|
126
126
|
* Resolve callback to fulfill the promise.
|
|
127
127
|
*/
|
|
128
|
-
readonly resolve: (value: Response) => void;
|
|
128
|
+
readonly resolve: (value: Response | PromiseLike<Response>) => void;
|
|
129
129
|
/**
|
|
130
130
|
* Reject callback to reject the promise.
|
|
131
131
|
*/
|
|
132
|
-
readonly reject: (reason?:
|
|
132
|
+
readonly reject: (reason?: unknown) => void;
|
|
133
133
|
/**
|
|
134
134
|
* The worker handling the execution.
|
|
135
135
|
*/
|
|
@@ -36,9 +36,9 @@ export declare abstract class AbstractWorker<MainWorker extends Worker | Message
|
|
|
36
36
|
*/
|
|
37
37
|
protected statistics: WorkerStatistics;
|
|
38
38
|
/**
|
|
39
|
-
* Handler id of the `
|
|
39
|
+
* Handler id of the `activeInterval` worker activity check.
|
|
40
40
|
*/
|
|
41
|
-
protected
|
|
41
|
+
protected activeInterval?: NodeJS.Timeout;
|
|
42
42
|
/**
|
|
43
43
|
* Constructs a new poolifier worker.
|
|
44
44
|
*
|
|
@@ -99,25 +99,25 @@ export declare abstract class AbstractWorker<MainWorker extends Worker | Message
|
|
|
99
99
|
/**
|
|
100
100
|
* Worker message listener.
|
|
101
101
|
*
|
|
102
|
-
* @param message -
|
|
102
|
+
* @param message - The received message.
|
|
103
103
|
*/
|
|
104
104
|
protected messageListener(message: MessageValue<Data, Data>): void;
|
|
105
105
|
/**
|
|
106
|
-
*
|
|
106
|
+
* Sends to the main worker the ready response.
|
|
107
107
|
*/
|
|
108
|
-
protected
|
|
108
|
+
protected sendReadyResponse(): void;
|
|
109
109
|
/**
|
|
110
|
-
* Starts the worker
|
|
110
|
+
* Starts the worker check active interval.
|
|
111
111
|
*/
|
|
112
|
-
private
|
|
112
|
+
private startCheckActive;
|
|
113
113
|
/**
|
|
114
|
-
* Stops the worker
|
|
114
|
+
* Stops the worker check active interval.
|
|
115
115
|
*/
|
|
116
|
-
private
|
|
116
|
+
private stopCheckActive;
|
|
117
117
|
/**
|
|
118
118
|
* Checks if the worker should be terminated, because its living too long.
|
|
119
119
|
*/
|
|
120
|
-
private
|
|
120
|
+
private checkActive;
|
|
121
121
|
/**
|
|
122
122
|
* Returns the main worker.
|
|
123
123
|
*
|
|
@@ -20,13 +20,13 @@ export type KillBehavior = keyof typeof KillBehaviors;
|
|
|
20
20
|
*/
|
|
21
21
|
export interface WorkerOptions {
|
|
22
22
|
/**
|
|
23
|
-
* Maximum waiting time in milliseconds for tasks.
|
|
23
|
+
* Maximum waiting time in milliseconds for tasks on newly created workers.
|
|
24
24
|
*
|
|
25
25
|
* After this time, newly created workers will be terminated.
|
|
26
|
-
* The last active time of your worker
|
|
26
|
+
* The last active time of your worker will be updated when it terminates a task.
|
|
27
27
|
*
|
|
28
28
|
* - If `killBehavior` is set to `KillBehaviors.HARD` this value represents also the timeout for the tasks that you submit to the pool,
|
|
29
|
-
* when this timeout expires your tasks is interrupted and
|
|
29
|
+
* when this timeout expires your tasks is interrupted before completion and removed. The worker is killed if is not part of the minimum size of the pool.
|
|
30
30
|
* - If `killBehavior` is set to `KillBehaviors.SOFT` your tasks have no timeout and your workers will not be terminated until your task is completed.
|
|
31
31
|
*
|
|
32
32
|
* @defaultValue 60000
|
|
@@ -40,7 +40,7 @@ export interface WorkerOptions {
|
|
|
40
40
|
*/
|
|
41
41
|
async?: boolean;
|
|
42
42
|
/**
|
|
43
|
-
* `killBehavior` dictates if your
|
|
43
|
+
* `killBehavior` dictates if your worker will be deleted in case a task is active on it.
|
|
44
44
|
*
|
|
45
45
|
* - SOFT: If `currentTime - lastActiveTime` is greater than `maxInactiveTime` but a task is still executing or queued, then the worker **won't** be deleted.
|
|
46
46
|
* - HARD: If `currentTime - lastActiveTime` is greater than `maxInactiveTime` but a task is still executing or queued, then the worker will be deleted.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "poolifier",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.15",
|
|
4
4
|
"description": "A fast, easy to use Node.js Worker Thread Pool and Cluster Pool implementation",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"volta": {
|
|
28
28
|
"node": "20.4.0",
|
|
29
|
-
"pnpm": "8.6.
|
|
29
|
+
"pnpm": "8.6.7"
|
|
30
30
|
},
|
|
31
31
|
"repository": {
|
|
32
32
|
"type": "git",
|
|
@@ -81,12 +81,12 @@
|
|
|
81
81
|
"@commitlint/cli": "^17.6.6",
|
|
82
82
|
"@commitlint/config-conventional": "^17.6.6",
|
|
83
83
|
"@release-it/bumper": "^5.0.0",
|
|
84
|
-
"@release-it/keep-a-changelog": "^
|
|
84
|
+
"@release-it/keep-a-changelog": "^4.0.0",
|
|
85
85
|
"@rollup/plugin-terser": "^0.4.3",
|
|
86
86
|
"@rollup/plugin-typescript": "^11.1.2",
|
|
87
87
|
"@types/node": "^20.4.1",
|
|
88
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
89
|
-
"@typescript-eslint/parser": "^5.
|
|
88
|
+
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
|
89
|
+
"@typescript-eslint/parser": "^5.62.0",
|
|
90
90
|
"benny": "^3.7.1",
|
|
91
91
|
"c8": "^8.0.0",
|
|
92
92
|
"eslint": "^8.44.0",
|