poolifier 2.6.18 → 2.6.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -1 +1 @@
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 h(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 u=h(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"}),l="default",m=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},f=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),T=(e,t,r,s)=>{t.aggregate&&(e.aggregate=(e.aggregate??0)+r,e.minimum=Math.min(r,e.minimum??1/0),e.maximum=Math.max(r,e.maximum??-1/0),t.average&&0!==s&&(e.average=e.aggregate/s),t.median&&null!=r&&(e.history.push(r),e.median=w(e.history)))},W=Object.freeze({SOFT:"SOFT",HARD:"HARD"}),x=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"}),N=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.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.runTime,e.runTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.waitTime,e.waitTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.elu,e.elu?.median)}toggleMedianMeasurementStatisticsRequirements(e,t){e.average&&t&&(e.average=!1,e.median=t),e.median&&!t&&(e.average=!0,e.median=t)}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 E 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===N.elu?this.getWorkerTaskElu(e):this.getWorkerTaskRunTime(e))}getWorkerVirtualTaskStartTimestamp(e){return Math.max(performance.now(),this.workersVirtualTaskEndTimestamp[e]??-1/0)}}class R 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 v 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 b 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 C 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 I 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 O 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 z{workerChoiceStrategy;workerChoiceStrategies;constructor(e,t=x.ROUND_ROBIN,r=g){this.workerChoiceStrategy=t,this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[x.ROUND_ROBIN,new(I.bind(this))(e,r)],[x.LEAST_USED,new(b.bind(this))(e,r)],[x.LEAST_BUSY,new(v.bind(this))(e,r)],[x.LEAST_ELU,new(C.bind(this))(e,r)],[x.FAIR_SHARE,new(E.bind(this))(e,r)],[x.WEIGHTED_ROUND_ROBIN,new(O.bind(this))(e,r)],[x.INTERLEAVED_WEIGHTED_ROUND_ROBIN,new(R.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 K{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 M=Object.freeze({cluster:"cluster",thread:"thread"});class A{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 K}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===M.thread?e.threadId:t===M.cluster?e.id:void 0}}class P{numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;starting;startTimestamp;constructor(e,t,r){if(this.numberOfWorkers=e,this.filePath=t,this.opts=r,!this.isMain())throw new Error("Cannot start a pool from a worker!");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 z(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook(),this.starting=!0,this.startPool(),this.starting=!1,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(!f(e))throw new TypeError("Invalid pool options: must be a plain object");this.opts.workerChoiceStrategy=e.workerChoiceStrategy??x.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(x).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)}checkValidWorkerChoiceStrategyOptions(e){if(!f(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(N).includes(e.measurement))throw new Error(`Invalid worker choice strategy options: invalid measurement '${e.measurement}'`)}checkValidTasksQueueOptions(e){if(null!=e&&!f(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}'`)}startPool(){for(;this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.numberOfWorkers;)this.createAndSetupWorker()}get info(){return{version:"2.6.18",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 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??l,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??l);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){T(e.runTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime,t.taskPerformance?.runTime??0,e.tasks.executed)}updateWaitTimeWorkerUsage(e,t){const r=s.performance.now(),i=r-(t.timestamp??r);T(e.waitTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime,i,e.tasks.executed)}updateEluWorkerUsage(e,t){const r=this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu;T(e.elu.active,r,t.taskPerformance?.elu?.active??0,e.tasks.executed),T(e.elu.idle,r,t.taskPerformance?.elu?.idle??0,e.tasks.executed),r.aggregate&&null!=t.taskPerformance?.elu&&(null!=e.elu.utilization?e.elu.utilization=(e.elu.utilization+t.taskPerformance.elu.utilization)/2:e.elu.utilization=t.taskPerformance.elu.utilization)}chooseWorkerNode(){if(this.shallCreateDynamicWorker()){const e=this.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??m),e.on("error",this.opts.errorHandler??m),e.on("error",(t=>{const r=this.getWorkerNodeKey(e),s=this.getWorkerInfo(r);s.ready=!1,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??m),e.on("exit",this.opts.exitHandler??m),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=W.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?(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 A(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 Q extends P{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 M.cluster}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}class U extends P{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 M.thread}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}const D=6e4,F=W.SOFT;class _ extends n.AsyncResource{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,r,s,i={killBehavior:F,maxInactiveTime:D}){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??F,this.opts.maxInactiveTime=e.maxInactiveTime??D,delete this.opts.async}checkTaskFunctions(e){if(null==e)throw new Error("taskFunctions parameter is mandatory");if(this.taskFunctions=new Map,"function"==typeof e){const t=e.bind(this);this.taskFunctions.set(l,t),this.taskFunctions.set("string"==typeof e.name&&e.name.trim().length>0?e.name:"fn1",t)}else{if(!f(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");const e=s.bind(this);t&&(this.taskFunctions.set(l,e),t=!1),this.taskFunctions.set(r,e)}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===l)throw new Error("Cannot add a task function with the default reserved name");if("function"!=typeof t)throw new TypeError("fn parameter is not a function");try{const r=t.bind(this);return this.taskFunctions.get(e)===this.taskFunctions.get(l)&&this.taskFunctions.set(l,r),this.taskFunctions.set(e,r),!0}catch{return!1}}removeTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===l)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(l))throw new Error("Cannot remove the task function used as the default task function");return this.taskFunctions.delete(e)}listTaskFunctions(){return Array.from(this.taskFunctions.keys())}setDefaultTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===l)throw new Error("Cannot set the default task function reserved name as the default task function");if(!this.taskFunctions.has(e))throw new Error("Cannot set the default task function to a non-existing task function");try{return this.taskFunctions.set(l,this.taskFunctions.get(e)),!0}catch{return!1}}messageListener(e){e.workerId===this.id&&(null!=e.ready?this.sendReadyResponse():null!=e.statistics?this.statistics=e.statistics:null!=e.checkActive?!this.isMain&&e.checkActive?this.startCheckActive():this.stopCheckActive():null!=e.id&&null!=e.data?this.run(e):!0===e.kill&&(!this.isMain&&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??D)/2).unref()}stopCheckActive(){null!=this.activeInterval&&(clearInterval(this.activeInterval),delete this.activeInterval)}checkActive(){s.performance.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??D)&&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){if(this.isMain)throw new Error("Cannot run a task in the main worker");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??l,message:r,data:t.data},workerId:this.id,id:t.id})}finally{this.updateLastTaskTimestamp()}}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??l,message:r,data:t.data},workerId:this.id,id:t.id})})).finally((()=>{this.updateLastTaskTimestamp()})).catch(m)}getTaskFunction(e){e=e??l;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??l,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")}updateLastTaskTimestamp(){this.isMain||null==this.activeInterval||(this.lastTaskTimestamp=s.performance.now())}}exports.ClusterWorker=class extends _{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 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.DynamicThreadPool=class extends U{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=Q,exports.FixedThreadPool=U,exports.KillBehaviors=W,exports.Measurements=N,exports.PoolEvents=d,exports.PoolTypes=k,exports.ThreadWorker=class extends _{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=x,exports.WorkerTypes=M,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"),s=require("node:crypto"),r=require("node:perf_hooks"),i=require("node:fs"),o=require("node:os"),n=require("node:worker_threads"),a=require("node:async_hooks");function h(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(s){if("default"!==s){var r=Object.getOwnPropertyDescriptor(e,s);Object.defineProperty(t,s,r.get?r:{enumerable:!0,get:function(){return e[s]}})}})),t.default=e,Object.freeze(t)}var u=h(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"}),l="default",m=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 s=Math.pow(10,t);return Math.round(e*s*(1+Number.EPSILON))/s},f=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),T=(e,t,s,r)=>{t.aggregate&&(e.aggregate=(e.aggregate??0)+s,e.minimum=Math.min(s,e.minimum??1/0),e.maximum=Math.max(s,e.maximum??-1/0),t.average&&0!==r&&(e.average=e.aggregate/r),t.median&&null!=s&&(e.history.push(s),e.median=w(e.history)))},W=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"}),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.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.runTime,e.runTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.waitTime,e.waitTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.elu,e.elu?.median)}toggleMedianMeasurementStatisticsRequirements(e,t){e.average&&t&&(e.average=!1,e.median=t),e.median&&!t&&(e.average=!0,e.median=t)}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 s=t.speed.toString().length-1;e+=1/(t.speed/Math.pow(10,s))*Math.pow(10,s)}return Math.round(e/o.cpus().length)}}class E 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 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===x.elu?this.getWorkerTaskElu(e):this.getWorkerTaskRunTime(e))}getWorkerVirtualTaskStartTimestamp(e){return Math.max(performance.now(),this.workersVirtualTaskEndTimestamp[e]??-1/0)}}class C 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 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 b 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,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 v 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,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 R 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,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 I 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 O 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 z{workerChoiceStrategy;workerChoiceStrategies;constructor(e,t=N.ROUND_ROBIN,s=g){this.workerChoiceStrategy=t,this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[N.ROUND_ROBIN,new(I.bind(this))(e,s)],[N.LEAST_USED,new(v.bind(this))(e,s)],[N.LEAST_BUSY,new(b.bind(this))(e,s)],[N.LEAST_ELU,new(R.bind(this))(e,s)],[N.FAIR_SHARE,new(E.bind(this))(e,s)],[N.WEIGHTED_ROUND_ROBIN,new(O.bind(this))(e,s)],[N.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 TypeError("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 M 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 K=Object.freeze({cluster:"cluster",thread:"thread"});class Q{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()}closeChannel(){null!=this.info.messageChannel&&(this.info.messageChannel?.port1.unref(),this.info.messageChannel?.port2.unref(),this.info.messageChannel?.port1.close(),this.info.messageChannel?.port2.close(),delete this.info.messageChannel)}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,...t===K.thread&&{messageChannel:new n.MessageChannel}}}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 M},waitTime:{history:new M},elu:{idle:{history:new M},active:{history:new M}}}}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 M},waitTime:{history:new M},elu:{idle:{history:new M},active:{history:new M}}}}getWorkerId(e,t){return t===K.thread?e.threadId:t===K.cluster?e.id:void 0}}class A{numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;starting;startTimestamp;constructor(e,t,s){if(this.numberOfWorkers=e,this.filePath=t,this.opts=s,!this.isMain())throw new Error("Cannot start a pool from a worker!");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.dequeueTask=this.dequeueTask.bind(this),this.checkAndEmitEvents=this.checkAndEmitEvents.bind(this),!0===this.opts.enableEvents&&(this.emitter=new c),this.workerChoiceStrategyContext=new z(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook(),this.starting=!0,this.startPool(),this.starting=!1,this.startTimestamp=r.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(null==t)throw new Error("Cannot instantiate a dynamic pool without specifying the maximum pool size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot instantiate a dynamic pool with a non safe integer maximum pool size");if(e>t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size");if(0===t)throw new RangeError("Cannot instantiate a dynamic pool with a 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(!f(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??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(N).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)}checkValidWorkerChoiceStrategyOptions(e){if(!f(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&&!f(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}'`)}startPool(){for(;this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.numberOfWorkers;)this.createAndSetupWorkerNode()}get info(){return{version:"2.6.20",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 ready(){return this.workerNodes.reduce(((e,t)=>!t.info.dynamic&&t.info.ready?e+1:e),0)>=this.minSize}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}checkMessageWorkerId(e){if(null!=e.workerId&&-1===this.getWorkerNodeKeyByWorkerId(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKeyByWorker(e){return this.workerNodes.findIndex((t=>t.worker===e))}getWorkerNodeKeyByWorkerId(e){return this.workerNodes.findIndex((t=>t.info.id===e))}setWorkerChoiceStrategy(e,t){this.checkValidWorkerChoiceStrategy(e),this.opts.workerChoiceStrategy=e,this.workerChoiceStrategyContext.setWorkerChoiceStrategy(this.opts.workerChoiceStrategy),null!=t&&this.setWorkerChoiceStrategyOptions(t);for(const[e,t]of this.workerNodes.entries())t.resetUsage(),this.sendWorkerStatisticsMessageToWorker(e)}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=>e.info.ready&&0===e.usage.tasks.executing))}async execute(e,t){return await new Promise(((i,o)=>{const n=r.performance.now(),a=this.chooseWorkerNode(),h={name:t??l,data:e??{},timestamp:n,workerId:this.getWorkerInfo(a).id,id:s.randomUUID()};this.promiseResponseMap.set(h.id,{resolve:i,reject:o,workerNodeKey:a}),!1===this.opts.enableTasksQueue||!0===this.opts.enableTasksQueue&&this.workerNodes[a].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency?this.executeTask(a,h):this.enqueueTask(a,h),this.checkAndEmitEvents()}))}async destroy(){await Promise.all(this.workerNodes.map((async(e,t)=>{await this.destroyWorkerNode(t)})))}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.workerNodes[e].usage;this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t);const r=this.workerNodes[e].getTaskWorkerUsage(t.taskPerformance?.name??l);this.updateTaskStatisticsWorkerUsage(r,t),this.updateRunTimeWorkerUsage(r,t),this.updateEluWorkerUsage(r,t)}updateTaskStatisticsWorkerUsage(e,t){const s=e.tasks;--s.executing,null==t.taskError?++s.executed:++s.failed}updateRunTimeWorkerUsage(e,t){T(e.runTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime,t.taskPerformance?.runTime??0,e.tasks.executed)}updateWaitTimeWorkerUsage(e,t){const s=r.performance.now(),i=s-(t.timestamp??s);T(e.waitTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime,i,e.tasks.executed)}updateEluWorkerUsage(e,t){const s=this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu;T(e.elu.active,s,t.taskPerformance?.elu?.active??0,e.tasks.executed),T(e.elu.idle,s,t.taskPerformance?.elu?.idle??0,e.tasks.executed),s.aggregate&&null!=t.taskPerformance?.elu&&(null!=e.elu.utilization?e.elu.utilization=(e.elu.utilization+t.taskPerformance.elu.utilization)/2:e.elu.utilization=t.taskPerformance.elu.utilization)}chooseWorkerNode(){if(this.shallCreateDynamicWorker()){const e=this.createAndSetupDynamicWorkerNode();if(this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker)return e}return this.workerChoiceStrategyContext.execute()}shallCreateDynamicWorker(){return this.type===k.dynamic&&!this.full&&this.internalBusy()}createAndSetupWorkerNode(){const e=this.createWorker();e.on("message",this.opts.messageHandler??m),e.on("error",this.opts.errorHandler??m),e.on("error",(t=>{const s=this.getWorkerNodeKeyByWorker(e),r=this.getWorkerInfo(s);r.ready=!1,this.workerNodes[s].closeChannel(),this.emitter?.emit(d.error,t),!0!==this.opts.restartWorkerOnError||this.starting||(r.dynamic?this.createAndSetupDynamicWorkerNode():this.createAndSetupWorkerNode()),!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(s)})),e.on("online",this.opts.onlineHandler??m),e.on("exit",this.opts.exitHandler??m),e.once("exit",(()=>{this.removeWorkerNode(e)}));const t=this.addWorkerNode(e);return this.afterWorkerNodeSetup(t),t}createAndSetupDynamicWorkerNode(){const e=this.createAndSetupWorkerNode();this.registerWorkerMessageListener(e,(e=>{const t=this.getWorkerNodeKeyByWorkerId(e.workerId),s=this.workerNodes[t].usage;var r;r=W.HARD,(e.kill===r||null!=e.kill&&(!1===this.opts.enableTasksQueue&&0===s.tasks.executing||!0===this.opts.enableTasksQueue&&0===s.tasks.executing&&0===this.tasksQueueSize(t)))&&this.destroyWorkerNode(t).catch(m)}));const t=this.getWorkerInfo(e);return this.sendToWorker(e,{checkActive:!0,workerId:t.id}),t.dynamic=!0,this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker&&(t.ready=!0),e}afterWorkerNodeSetup(e){this.registerWorkerMessageListener(e,this.workerListener()),this.sendStartupMessageToWorker(e),this.sendWorkerStatisticsMessageToWorker(e)}sendWorkerStatisticsMessageToWorker(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate},workerId:this.getWorkerInfo(e).id})}redistributeQueuedTasks(e){for(;this.tasksQueueSize(e)>0;){let t=e,s=1/0,r=!1;for(const[i,o]of this.workerNodes.entries()){const n=this.getWorkerInfo(i);if(i!==e&&n.ready&&0===o.usage.tasks.queued){this.workerNodes[i].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&(r=!0),t=i;break}i!==e&&n.ready&&o.usage.tasks.queued<s&&(s=o.usage.tasks.queued,t=i)}r?this.executeTask(t,this.dequeueTask(e)):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){this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId)).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?(this.emitter?.emit(d.taskError,e.taskError),t.reject(e.taskError.message)):t.resolve(e.data);const s=t.workerNodeKey;this.afterTaskExecutionHook(s,e),this.promiseResponseMap.delete(e.id),!0===this.opts.enableTasksQueue&&this.tasksQueueSize(s)>0&&this.workerNodes[s].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&this.executeTask(s,this.dequeueTask(s)),this.workerChoiceStrategyContext.update(s)}}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 Q(e,this.worker);this.starting&&(t.info.ready=!0),this.workerNodes.push(t);const s=this.getWorkerNodeKeyByWorker(e);if(-1===s)throw new Error("Worker node not found");return s}removeWorkerNode(e){const t=this.getWorkerNodeKeyByWorker(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategyContext.remove(t))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(e,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)}}class P extends A{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}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e].worker,s=new Promise((e=>{t.on("exit",(()=>{e()}))}));t.on("disconnect",(()=>{t.kill()})),this.sendToWorker(e,{kill:!0,workerId:t.id}),t.disconnect(),await s}sendToWorker(e,t){this.workerNodes[e].worker.send(t)}sendStartupMessageToWorker(e){this.sendToWorker(e,{ready:!1,workerId:this.workerNodes[e].worker.id})}registerWorkerMessageListener(e,t){this.workerNodes[e].worker.on("message",t)}createWorker(){return 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 U extends A{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}isMain(){return n.isMainThread}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e],s=t.worker,r=new Promise((e=>{s.on("exit",(()=>{e()}))}));this.sendToWorker(e,{kill:!0,workerId:s.threadId}),t.closeChannel(),await s.terminate(),await r}sendToWorker(e,t){this.getWorkerInfo(e).messageChannel.port1.postMessage(t)}sendStartupMessageToWorker(e){const t=this.workerNodes[e].worker,s=this.getWorkerInfo(e).messageChannel.port2;t.postMessage({ready:!1,workerId:t.threadId,port:s},[s])}registerWorkerMessageListener(e,t){this.getWorkerInfo(e).messageChannel.port1.on("message",t)}createWorker(){return new n.Worker(this.filePath,{env:n.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 D=6e4,F=W.SOFT;class _ extends a.AsyncResource{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,s,r,i={killBehavior:F,maxInactiveTime:D}){super(e),this.isMain=t,this.mainWorker=s,this.opts=i,this.checkWorkerOptions(this.opts),this.checkTaskFunctions(r),this.isMain||this.getMainWorker()?.on("message",this.handleReadyMessage.bind(this))}checkWorkerOptions(e){this.opts.killBehavior=e.killBehavior??F,this.opts.maxInactiveTime=e.maxInactiveTime??D,delete this.opts.async}checkTaskFunctions(e){if(null==e)throw new Error("taskFunctions parameter is mandatory");if(this.taskFunctions=new Map,"function"==typeof e){const t=e.bind(this);this.taskFunctions.set(l,t),this.taskFunctions.set("string"==typeof e.name&&e.name.trim().length>0?e.name:"fn1",t)}else{if(!f(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");const e=r.bind(this);t&&(this.taskFunctions.set(l,e),t=!1),this.taskFunctions.set(s,e)}if(t)throw new Error("taskFunctions parameter object is empty")}}}hasTaskFunction(e){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===l)throw new Error("Cannot add a task function with the default reserved name");if("function"!=typeof t)throw new TypeError("fn parameter is not a function");try{const s=t.bind(this);return this.taskFunctions.get(e)===this.taskFunctions.get(l)&&this.taskFunctions.set(l,s),this.taskFunctions.set(e,s),!0}catch{return!1}}removeTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===l)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(l))throw new Error("Cannot remove the task function used as the default task function");return this.taskFunctions.delete(e)}listTaskFunctions(){return Array.from(this.taskFunctions.keys())}setDefaultTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===l)throw new Error("Cannot set the default task function reserved name as the default task function");if(!this.taskFunctions.has(e))throw new Error("Cannot set the default task function to a non-existing task function");try{return this.taskFunctions.set(l,this.taskFunctions.get(e)),!0}catch{return!1}}messageListener(e){e.workerId===this.id&&(null!=e.statistics?this.statistics=e.statistics:null!=e.checkActive?!this.isMain&&e.checkActive?this.startCheckActive():this.stopCheckActive():null!=e.id&&null!=e.data?this.run(e):!0===e.kill&&this.handleKillMessage(e))}handleKillMessage(e){!this.isMain&&this.stopCheckActive(),this.emitDestroy()}startCheckActive(){this.lastTaskTimestamp=r.performance.now(),this.activeInterval=setInterval(this.checkActive.bind(this),(this.opts.maxInactiveTime??D)/2)}stopCheckActive(){null!=this.activeInterval&&(clearInterval(this.activeInterval),delete this.activeInterval)}checkActive(){r.performance.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??D)&&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){if(this.isMain)throw new Error("Cannot run a task in the main worker");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??l,message:s,data:t.data},workerId:this.id,id:t.id})}finally{this.updateLastTaskTimestamp()}}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??l,message:s,data:t.data},workerId:this.id,id:t.id})})).finally((()=>{this.updateLastTaskTimestamp()})).catch(m)}getTaskFunction(e){e=e??l;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??l,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")}updateLastTaskTimestamp(){this.isMain||null==this.activeInterval||(this.lastTaskTimestamp=r.performance.now())}}exports.ClusterWorker=class extends _{constructor(e,s={}){super("worker-cluster-pool:poolifier",t.isPrimary,t.worker,e,s)}handleReadyMessage(e){this.isMain||e.workerId!==this.id||null==e.ready||(this.getMainWorker()?.on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,workerId:this.id}))}get id(){return this.getMainWorker().id}sendToMainWorker(e){this.getMainWorker().send(e)}},exports.DynamicClusterPool=class extends P{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return k.dynamic}get maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}},exports.DynamicThreadPool=class extends U{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return k.dynamic}get maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}},exports.FixedClusterPool=P,exports.FixedThreadPool=U,exports.KillBehaviors=W,exports.Measurements=x,exports.PoolEvents=d,exports.PoolTypes=k,exports.ThreadWorker=class extends _{port;constructor(e,t={}){super("worker-thread-pool:poolifier",n.isMainThread,n.parentPort,e,t)}handleReadyMessage(e){this.isMain||e.workerId!==this.id||null==e.ready||null==e.port||(this.port=e.port,this.port.on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,workerId:this.id}))}handleKillMessage(e){super.handleKillMessage(e),this.port?.unref(),this.port?.close()}get id(){return n.threadId}sendToMainWorker(e){this.port.postMessage(e)}handleError(e){return e}},exports.WorkerChoiceStrategies=N,exports.WorkerTypes=K,exports.availableParallelism=()=>{let e=1;try{e=u.availableParallelism()}catch{const t=u.cpus();Array.isArray(t)&&t.length>0&&(e=t.length)}return e};
package/lib/index.mjs CHANGED
@@ -1 +1 @@
1
- import{EventEmitter as e}from"node:events";import 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 n}from"node:os";import{isMainThread as a,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 l=Object.freeze({fixed:"fixed",dynamic:"dynamic"});class m extends e{}const g=Object.freeze({full:"full",ready:"ready",busy:"busy",error:"error",taskError:"taskError"}),p="default",w=Object.freeze((()=>{})),y={runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},f={aggregate:!1,average:!1,median:!1},T=()=>{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},N=(e,t=2)=>{const s=Math.pow(10,t);return Math.round(e*s*(1+Number.EPSILON))/s},x=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),S=(e,t,s,r)=>{t.aggregate&&(e.aggregate=(e.aggregate??0)+s,e.minimum=Math.min(s,e.minimum??1/0),e.maximum=Math.max(s,e.maximum??-1/0),t.average&&0!==r&&(e.average=e.aggregate/r),t.median&&null!=s&&(e.history.push(s),e.median=W(e.history)))},E=Object.freeze({SOFT:"SOFT",HARD:"HARD"}),R=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 b{pool;opts;nextWorkerNodeKey=0;strategyPolicy={useDynamicWorker:!1};taskStatisticsRequirements={runTime:f,waitTime:f,elu:f};constructor(e,t=y){this.pool=e,this.opts=t,this.choose=this.choose.bind(this)}setTaskStatisticsRequirements(e){this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.runTime,e.runTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.waitTime,e.waitTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.elu,e.elu?.median)}toggleMedianMeasurementStatisticsRequirements(e,t){e.average&&t&&(e.average=!1,e.median=t),e.median&&!t&&(e.average=!0,e.median=t)}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 n()){const s=t.speed.toString().length-1;e+=1/(t.speed/Math.pow(10,s))*Math.pow(10,s)}return Math.round(e/n().length)}}class C extends b{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:f,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===v.elu?this.getWorkerTaskElu(e):this.getWorkerTaskRunTime(e))}getWorkerVirtualTaskStartTimestamp(e){return Math.max(performance.now(),this.workersVirtualTaskEndTimestamp[e]??-1/0)}}class I extends b{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 O extends b{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:f};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 z extends b{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 K extends b{taskStatisticsRequirements={runTime:f,waitTime:f,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 b{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 M extends b{strategyPolicy={useDynamicWorker:!0};taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:f,elu:f};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 A{workerChoiceStrategy;workerChoiceStrategies;constructor(e,t=R.ROUND_ROBIN,s=y){this.workerChoiceStrategy=t,this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[R.ROUND_ROBIN,new(q.bind(this))(e,s)],[R.LEAST_USED,new(z.bind(this))(e,s)],[R.LEAST_BUSY,new(O.bind(this))(e,s)],[R.LEAST_ELU,new(K.bind(this))(e,s)],[R.FAIR_SHARE,new(C.bind(this))(e,s)],[R.WEIGHTED_ROUND_ROBIN,new(M.bind(this))(e,s)],[R.INTERLEAVED_WEIGHTED_ROUND_ROBIN,new(I.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 U{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 D{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 U}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 F{numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;starting;startTimestamp;constructor(e,t,s){if(this.numberOfWorkers=e,this.filePath=t,this.opts=s,!this.isMain())throw new Error("Cannot start a pool from a worker!");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 A(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook(),this.starting=!0,this.startPool(),this.starting=!1,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===l.fixed&&0===e)throw new RangeError("Cannot instantiate a fixed pool with zero worker")}checkDynamicPoolSize(e,t){if(this.type===l.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??R.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(R).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(v).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}'`)}startPool(){for(;this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.numberOfWorkers;)this.createAndSetupWorker()}get info(){return{version:"2.6.18",type:this.type,worker:this.worker,ready:this.ready,strategy:this.opts.workerChoiceStrategy,minSize:this.minSize,maxSize:this.maxSize,...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{utilization:N(this.utilization)},workerNodes:this.workerNodes.length,idleWorkerNodes:this.workerNodes.reduce(((e,t)=>0===t.usage.tasks.executing?e+1:e),0),busyWorkerNodes:this.workerNodes.reduce(((e,t)=>t.usage.tasks.executing>0?e+1:e),0),executedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executed),0),executingTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executing),0),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:N(Math.min(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:N(Math.max(...this.workerNodes.map((e=>e.usage.runTime?.maximum??-1/0)))),average:N(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:N(W(this.workerNodes.map((e=>e.usage.runTime?.median??0))))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:N(Math.min(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:N(Math.max(...this.workerNodes.map((e=>e.usage.waitTime?.maximum??-1/0)))),average:N(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:N(W(this.workerNodes.map((e=>e.usage.waitTime?.median??0))))}}}}}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(),n={name:t??p,data:e??{},timestamp:i,workerId:this.getWorkerInfo(o).id,id:s()},a=new Promise(((e,t)=>{this.promiseResponseMap.set(n.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,n):this.executeTask(o,n),this.checkAndEmitEvents(),a}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??p);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){S(e.runTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime,t.taskPerformance?.runTime??0,e.tasks.executed)}updateWaitTimeWorkerUsage(e,t){const s=r.now(),i=s-(t.timestamp??s);S(e.waitTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime,i,e.tasks.executed)}updateEluWorkerUsage(e,t){const s=this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu;S(e.elu.active,s,t.taskPerformance?.elu?.active??0,e.tasks.executed),S(e.elu.idle,s,t.taskPerformance?.elu?.idle??0,e.tasks.executed),s.aggregate&&null!=t.taskPerformance?.elu&&(null!=e.elu.utilization?e.elu.utilization=(e.elu.utilization+t.taskPerformance.elu.utilization)/2:e.elu.utilization=t.taskPerformance.elu.utilization)}chooseWorkerNode(){if(this.shallCreateDynamicWorker()){const e=this.createAndSetupDynamicWorker();if(this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker)return this.getWorkerNodeKey(e)}return this.workerChoiceStrategyContext.execute()}shallCreateDynamicWorker(){return this.type===l.dynamic&&!this.full&&this.internalBusy()}createAndSetupWorker(){const e=this.createWorker();return e.on("message",this.opts.messageHandler??w),e.on("error",this.opts.errorHandler??w),e.on("error",(t=>{const s=this.getWorkerNodeKey(e),r=this.getWorkerInfo(s);r.ready=!1,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??w),e.on("exit",this.opts.exitHandler??w),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=E.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?(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===l.dynamic&&this.full&&this.emitter.emit(g.full,this.info))}getWorkerInfo(e){return this.workerNodes[e].info}addWorkerNode(e){const t=new D(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 _ extends F{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 l.fixed}get worker(){return P.cluster}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}class V extends _{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return l.dynamic}get maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}}class B extends F{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 h(this.filePath,{env:u,...this.opts.workerOptions})}get type(){return l.fixed}get worker(){return P.thread}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}class L extends B{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return l.dynamic}get maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}}const j=6e4,H=E.SOFT;class $ extends d{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,s,r,i={killBehavior:H,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??H,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){const t=e.bind(this);this.taskFunctions.set(p,t),this.taskFunctions.set("string"==typeof e.name&&e.name.trim().length>0?e.name:"fn1",t)}else{if(!x(e))throw new TypeError("taskFunctions parameter is not a function or a plain object");{let t=!0;for(const[s,r]of Object.entries(e)){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");const e=r.bind(this);t&&(this.taskFunctions.set(p,e),t=!1),this.taskFunctions.set(s,e)}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===p)throw new Error("Cannot add a task function with the default reserved name");if("function"!=typeof t)throw new TypeError("fn parameter is not a function");try{const s=t.bind(this);return this.taskFunctions.get(e)===this.taskFunctions.get(p)&&this.taskFunctions.set(p,s),this.taskFunctions.set(e,s),!0}catch{return!1}}removeTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===p)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(p))throw new Error("Cannot remove the task function used as the default task function");return this.taskFunctions.delete(e)}listTaskFunctions(){return Array.from(this.taskFunctions.keys())}setDefaultTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===p)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(p,this.taskFunctions.get(e)),!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?!this.isMain&&e.checkActive?this.startCheckActive():this.stopCheckActive():null!=e.id&&null!=e.data?this.run(e):!0===e.kill&&(!this.isMain&&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).unref()}stopCheckActive(){null!=this.activeInterval&&(clearInterval(this.activeInterval),delete 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){if(this.isMain)throw new Error("Cannot run a task in the main worker");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??p,message:s,data:t.data},workerId:this.id,id:t.id})}finally{this.updateLastTaskTimestamp()}}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??p,message:s,data:t.data},workerId:this.id,id:t.id})})).finally((()=>{this.updateLastTaskTimestamp()})).catch(w)}getTaskFunction(e){e=e??p;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??p,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")}updateLastTaskTimestamp(){this.isMain||null==this.activeInterval||(this.lastTaskTimestamp=r.now())}}class G extends ${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 Y extends ${constructor(e,t={}){super("worker-thread-pool:poolifier",a,e,k,t)}get id(){return c}sendToMainWorker(e){this.getMainWorker().postMessage(e)}handleError(e){return e}}export{G as ClusterWorker,V as DynamicClusterPool,L as DynamicThreadPool,_ as FixedClusterPool,B as FixedThreadPool,E as KillBehaviors,v as Measurements,g as PoolEvents,l as PoolTypes,Y as ThreadWorker,R as WorkerChoiceStrategies,P as WorkerTypes,T 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 n}from"node:os";import{MessageChannel as a,isMainThread as h,Worker as u,SHARE_ENV as k,parentPort as c,threadId as d}from"node:worker_threads";import{AsyncResource as l}from"node:async_hooks";const m=Object.freeze({fixed:"fixed",dynamic:"dynamic"});class g extends e{}const p=Object.freeze({full:"full",ready:"ready",busy:"busy",error:"error",taskError:"taskError"}),w="default",y=Object.freeze((()=>{})),f={runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},T={aggregate:!1,average:!1,median:!1},W=()=>{let e=1;try{e=o.availableParallelism()}catch{const t=o.cpus();Array.isArray(t)&&t.length>0&&(e=t.length)}return e},N=e=>{if(Array.isArray(e)&&0===e.length)return 0;if(Array.isArray(e)&&1===e.length)return e[0];const t=e.slice().sort(((e,t)=>e-t));return(t[t.length-1>>1]+t[t.length>>1])/2},x=(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),E=(e,t,s,r)=>{t.aggregate&&(e.aggregate=(e.aggregate??0)+s,e.minimum=Math.min(s,e.minimum??1/0),e.maximum=Math.max(s,e.maximum??-1/0),t.average&&0!==r&&(e.average=e.aggregate/r),t.median&&null!=s&&(e.history.push(s),e.median=N(e.history)))},R=Object.freeze({SOFT:"SOFT",HARD:"HARD"}),C=Object.freeze({ROUND_ROBIN:"ROUND_ROBIN",LEAST_USED:"LEAST_USED",LEAST_BUSY:"LEAST_BUSY",LEAST_ELU:"LEAST_ELU",FAIR_SHARE:"FAIR_SHARE",WEIGHTED_ROUND_ROBIN:"WEIGHTED_ROUND_ROBIN",INTERLEAVED_WEIGHTED_ROUND_ROBIN:"INTERLEAVED_WEIGHTED_ROUND_ROBIN"}),b=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"});class v{pool;opts;nextWorkerNodeKey=0;strategyPolicy={useDynamicWorker:!1};taskStatisticsRequirements={runTime:T,waitTime:T,elu:T};constructor(e,t=f){this.pool=e,this.opts=t,this.choose=this.choose.bind(this)}setTaskStatisticsRequirements(e){this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.runTime,e.runTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.waitTime,e.waitTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.elu,e.elu?.median)}toggleMedianMeasurementStatisticsRequirements(e,t){e.average&&t&&(e.average=!1,e.median=t),e.median&&!t&&(e.average=!0,e.median=t)}setOptions(e){this.opts=e??f,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 n()){const s=t.speed.toString().length-1;e+=1/(t.speed/Math.pow(10,s))*Math.pow(10,s)}return Math.round(e/n().length)}}class I extends v{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:T,elu:{aggregate:!0,average:!0,median:!1}};workersVirtualTaskEndTimestamp=[];constructor(e,t=f){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===b.elu?this.getWorkerTaskElu(e):this.getWorkerTaskRunTime(e))}getWorkerVirtualTaskStartTimestamp(e){return Math.max(performance.now(),this.workersVirtualTaskEndTimestamp[e]??-1/0)}}class O extends v{strategyPolicy={useDynamicWorker:!0};roundId=0;roundWeights;defaultWorkerWeight;constructor(e,t=f){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 z extends v{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:T};constructor(e,t=f){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 M extends v{constructor(e,t=f){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 K extends v{taskStatisticsRequirements={runTime:T,waitTime:T,elu:{aggregate:!0,average:!1,median:!1}};constructor(e,t=f){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 v{strategyPolicy={useDynamicWorker:!0};constructor(e,t=f){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 Q extends v{strategyPolicy={useDynamicWorker:!0};taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:T,elu:T};defaultWorkerWeight;workerVirtualTaskRunTime=0;constructor(e,t=f){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 A{workerChoiceStrategy;workerChoiceStrategies;constructor(e,t=C.ROUND_ROBIN,s=f){this.workerChoiceStrategy=t,this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[C.ROUND_ROBIN,new(q.bind(this))(e,s)],[C.LEAST_USED,new(M.bind(this))(e,s)],[C.LEAST_BUSY,new(z.bind(this))(e,s)],[C.LEAST_ELU,new(K.bind(this))(e,s)],[C.FAIR_SHARE,new(I.bind(this))(e,s)],[C.WEIGHTED_ROUND_ROBIN,new(Q.bind(this))(e,s)],[C.INTERLEAVED_WEIGHTED_ROUND_ROBIN,new(O.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 TypeError("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 U extends Array{size;constructor(e=1024,...t){super(),this.checkSize(e),this.size=e,arguments.length>1&&this.push(...t)}push(...e){const t=super.push(...e);return t>this.size&&super.splice(0,t-this.size),this.length}unshift(...e){return super.unshift(...e)>this.size&&super.splice(this.size,e.length),this.length}concat(...e){const t=super.concat(e);return t.size=this.size,t.length>t.size&&t.splice(0,t.length-t.size),t}splice(e,t,...s){let r;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 P{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 D=Object.freeze({cluster:"cluster",thread:"thread"});class F{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 P}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()}closeChannel(){null!=this.info.messageChannel&&(this.info.messageChannel?.port1.unref(),this.info.messageChannel?.port2.unref(),this.info.messageChannel?.port1.close(),this.info.messageChannel?.port2.close(),delete this.info.messageChannel)}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,...t===D.thread&&{messageChannel:new a}}}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 U},waitTime:{history:new U},elu:{idle:{history:new U},active:{history:new U}}}}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 U},waitTime:{history:new U},elu:{idle:{history:new U},active:{history:new U}}}}getWorkerId(e,t){return t===D.thread?e.threadId:t===D.cluster?e.id:void 0}}class _{numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;starting;startTimestamp;constructor(e,t,s){if(this.numberOfWorkers=e,this.filePath=t,this.opts=s,!this.isMain())throw new Error("Cannot start a pool from a worker!");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.dequeueTask=this.dequeueTask.bind(this),this.checkAndEmitEvents=this.checkAndEmitEvents.bind(this),!0===this.opts.enableEvents&&(this.emitter=new g),this.workerChoiceStrategyContext=new A(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook(),this.starting=!0,this.startPool(),this.starting=!1,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(null==t)throw new Error("Cannot instantiate a dynamic pool without specifying the maximum pool size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot instantiate a dynamic pool with a non safe integer maximum pool size");if(e>t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size");if(0===t)throw new RangeError("Cannot instantiate a dynamic pool with a 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??C.ROUND_ROBIN,this.checkValidWorkerChoiceStrategy(this.opts.workerChoiceStrategy),this.opts.workerChoiceStrategyOptions=e.workerChoiceStrategyOptions??f,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(C).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(b).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}'`)}startPool(){for(;this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.numberOfWorkers;)this.createAndSetupWorkerNode()}get info(){return{version:"2.6.20",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:x(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:x(Math.min(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:x(Math.max(...this.workerNodes.map((e=>e.usage.runTime?.maximum??-1/0)))),average:x(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:x(N(this.workerNodes.map((e=>e.usage.runTime?.median??0))))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:x(Math.min(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:x(Math.max(...this.workerNodes.map((e=>e.usage.waitTime?.maximum??-1/0)))),average:x(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:x(N(this.workerNodes.map((e=>e.usage.waitTime?.median??0))))}}}}}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}checkMessageWorkerId(e){if(null!=e.workerId&&-1===this.getWorkerNodeKeyByWorkerId(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKeyByWorker(e){return this.workerNodes.findIndex((t=>t.worker===e))}getWorkerNodeKeyByWorkerId(e){return this.workerNodes.findIndex((t=>t.info.id===e))}setWorkerChoiceStrategy(e,t){this.checkValidWorkerChoiceStrategy(e),this.opts.workerChoiceStrategy=e,this.workerChoiceStrategyContext.setWorkerChoiceStrategy(this.opts.workerChoiceStrategy),null!=t&&this.setWorkerChoiceStrategyOptions(t);for(const[e,t]of this.workerNodes.entries())t.resetUsage(),this.sendWorkerStatisticsMessageToWorker(e)}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=>e.info.ready&&0===e.usage.tasks.executing))}async execute(e,t){return await new Promise(((i,o)=>{const n=r.now(),a=this.chooseWorkerNode(),h={name:t??w,data:e??{},timestamp:n,workerId:this.getWorkerInfo(a).id,id:s()};this.promiseResponseMap.set(h.id,{resolve:i,reject:o,workerNodeKey:a}),!1===this.opts.enableTasksQueue||!0===this.opts.enableTasksQueue&&this.workerNodes[a].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency?this.executeTask(a,h):this.enqueueTask(a,h),this.checkAndEmitEvents()}))}async destroy(){await Promise.all(this.workerNodes.map((async(e,t)=>{await this.destroyWorkerNode(t)})))}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.workerNodes[e].usage;this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t);const r=this.workerNodes[e].getTaskWorkerUsage(t.taskPerformance?.name??w);this.updateTaskStatisticsWorkerUsage(r,t),this.updateRunTimeWorkerUsage(r,t),this.updateEluWorkerUsage(r,t)}updateTaskStatisticsWorkerUsage(e,t){const s=e.tasks;--s.executing,null==t.taskError?++s.executed:++s.failed}updateRunTimeWorkerUsage(e,t){E(e.runTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime,t.taskPerformance?.runTime??0,e.tasks.executed)}updateWaitTimeWorkerUsage(e,t){const s=r.now(),i=s-(t.timestamp??s);E(e.waitTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime,i,e.tasks.executed)}updateEluWorkerUsage(e,t){const s=this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu;E(e.elu.active,s,t.taskPerformance?.elu?.active??0,e.tasks.executed),E(e.elu.idle,s,t.taskPerformance?.elu?.idle??0,e.tasks.executed),s.aggregate&&null!=t.taskPerformance?.elu&&(null!=e.elu.utilization?e.elu.utilization=(e.elu.utilization+t.taskPerformance.elu.utilization)/2:e.elu.utilization=t.taskPerformance.elu.utilization)}chooseWorkerNode(){if(this.shallCreateDynamicWorker()){const e=this.createAndSetupDynamicWorkerNode();if(this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker)return e}return this.workerChoiceStrategyContext.execute()}shallCreateDynamicWorker(){return this.type===m.dynamic&&!this.full&&this.internalBusy()}createAndSetupWorkerNode(){const e=this.createWorker();e.on("message",this.opts.messageHandler??y),e.on("error",this.opts.errorHandler??y),e.on("error",(t=>{const s=this.getWorkerNodeKeyByWorker(e),r=this.getWorkerInfo(s);r.ready=!1,this.workerNodes[s].closeChannel(),this.emitter?.emit(p.error,t),!0!==this.opts.restartWorkerOnError||this.starting||(r.dynamic?this.createAndSetupDynamicWorkerNode():this.createAndSetupWorkerNode()),!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(s)})),e.on("online",this.opts.onlineHandler??y),e.on("exit",this.opts.exitHandler??y),e.once("exit",(()=>{this.removeWorkerNode(e)}));const t=this.addWorkerNode(e);return this.afterWorkerNodeSetup(t),t}createAndSetupDynamicWorkerNode(){const e=this.createAndSetupWorkerNode();this.registerWorkerMessageListener(e,(e=>{const t=this.getWorkerNodeKeyByWorkerId(e.workerId),s=this.workerNodes[t].usage;var r;r=R.HARD,(e.kill===r||null!=e.kill&&(!1===this.opts.enableTasksQueue&&0===s.tasks.executing||!0===this.opts.enableTasksQueue&&0===s.tasks.executing&&0===this.tasksQueueSize(t)))&&this.destroyWorkerNode(t).catch(y)}));const t=this.getWorkerInfo(e);return this.sendToWorker(e,{checkActive:!0,workerId:t.id}),t.dynamic=!0,this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker&&(t.ready=!0),e}afterWorkerNodeSetup(e){this.registerWorkerMessageListener(e,this.workerListener()),this.sendStartupMessageToWorker(e),this.sendWorkerStatisticsMessageToWorker(e)}sendWorkerStatisticsMessageToWorker(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate},workerId:this.getWorkerInfo(e).id})}redistributeQueuedTasks(e){for(;this.tasksQueueSize(e)>0;){let t=e,s=1/0,r=!1;for(const[i,o]of this.workerNodes.entries()){const n=this.getWorkerInfo(i);if(i!==e&&n.ready&&0===o.usage.tasks.queued){this.workerNodes[i].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&(r=!0),t=i;break}i!==e&&n.ready&&o.usage.tasks.queued<s&&(s=o.usage.tasks.queued,t=i)}r?this.executeTask(t,this.dequeueTask(e)):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){this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId)).ready=e.ready,null!=this.emitter&&this.ready&&this.emitter.emit(p.ready,this.info)}handleTaskExecutionResponse(e){const t=this.promiseResponseMap.get(e.id);if(null!=t){null!=e.taskError?(this.emitter?.emit(p.taskError,e.taskError),t.reject(e.taskError.message)):t.resolve(e.data);const s=t.workerNodeKey;this.afterTaskExecutionHook(s,e),this.promiseResponseMap.delete(e.id),!0===this.opts.enableTasksQueue&&this.tasksQueueSize(s)>0&&this.workerNodes[s].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&this.executeTask(s,this.dequeueTask(s)),this.workerChoiceStrategyContext.update(s)}}checkAndEmitEvents(){null!=this.emitter&&(this.busy&&this.emitter.emit(p.busy,this.info),this.type===m.dynamic&&this.full&&this.emitter.emit(p.full,this.info))}getWorkerInfo(e){return this.workerNodes[e].info}addWorkerNode(e){const t=new F(e,this.worker);this.starting&&(t.info.ready=!0),this.workerNodes.push(t);const s=this.getWorkerNodeKeyByWorker(e);if(-1===s)throw new Error("Worker node not found");return s}removeWorkerNode(e){const t=this.getWorkerNodeKeyByWorker(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategyContext.remove(t))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(e,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)}}class B extends _{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}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e].worker,s=new Promise((e=>{t.on("exit",(()=>{e()}))}));t.on("disconnect",(()=>{t.kill()})),this.sendToWorker(e,{kill:!0,workerId:t.id}),t.disconnect(),await s}sendToWorker(e,t){this.workerNodes[e].worker.send(t)}sendStartupMessageToWorker(e){this.sendToWorker(e,{ready:!1,workerId:this.workerNodes[e].worker.id})}registerWorkerMessageListener(e,t){this.workerNodes[e].worker.on("message",t)}createWorker(){return t.fork(this.opts.env)}get type(){return m.fixed}get worker(){return D.cluster}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}class V extends B{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 L extends _{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}isMain(){return h}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e],s=t.worker,r=new Promise((e=>{s.on("exit",(()=>{e()}))}));this.sendToWorker(e,{kill:!0,workerId:s.threadId}),t.closeChannel(),await s.terminate(),await r}sendToWorker(e,t){this.getWorkerInfo(e).messageChannel.port1.postMessage(t)}sendStartupMessageToWorker(e){const t=this.workerNodes[e].worker,s=this.getWorkerInfo(e).messageChannel.port2;t.postMessage({ready:!1,workerId:t.threadId,port:s},[s])}registerWorkerMessageListener(e,t){this.getWorkerInfo(e).messageChannel.port1.on("message",t)}createWorker(){return new u(this.filePath,{env:k,...this.opts.workerOptions})}get type(){return m.fixed}get worker(){return D.thread}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}class j extends L{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 H=6e4,$=R.SOFT;class G extends l{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,s,r,i={killBehavior:$,maxInactiveTime:H}){super(e),this.isMain=t,this.mainWorker=s,this.opts=i,this.checkWorkerOptions(this.opts),this.checkTaskFunctions(r),this.isMain||this.getMainWorker()?.on("message",this.handleReadyMessage.bind(this))}checkWorkerOptions(e){this.opts.killBehavior=e.killBehavior??$,this.opts.maxInactiveTime=e.maxInactiveTime??H,delete this.opts.async}checkTaskFunctions(e){if(null==e)throw new Error("taskFunctions parameter is mandatory");if(this.taskFunctions=new Map,"function"==typeof e){const t=e.bind(this);this.taskFunctions.set(w,t),this.taskFunctions.set("string"==typeof e.name&&e.name.trim().length>0?e.name:"fn1",t)}else{if(!S(e))throw new TypeError("taskFunctions parameter is not a function or a plain object");{let t=!0;for(const[s,r]of Object.entries(e)){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");const e=r.bind(this);t&&(this.taskFunctions.set(w,e),t=!1),this.taskFunctions.set(s,e)}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{const s=t.bind(this);return this.taskFunctions.get(e)===this.taskFunctions.get(w)&&this.taskFunctions.set(w,s),this.taskFunctions.set(e,s),!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)}listTaskFunctions(){return Array.from(this.taskFunctions.keys())}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)),!0}catch{return!1}}messageListener(e){e.workerId===this.id&&(null!=e.statistics?this.statistics=e.statistics:null!=e.checkActive?!this.isMain&&e.checkActive?this.startCheckActive():this.stopCheckActive():null!=e.id&&null!=e.data?this.run(e):!0===e.kill&&this.handleKillMessage(e))}handleKillMessage(e){!this.isMain&&this.stopCheckActive(),this.emitDestroy()}startCheckActive(){this.lastTaskTimestamp=r.now(),this.activeInterval=setInterval(this.checkActive.bind(this),(this.opts.maxInactiveTime??H)/2)}stopCheckActive(){null!=this.activeInterval&&(clearInterval(this.activeInterval),delete this.activeInterval)}checkActive(){r.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??H)&&this.sendToMainWorker({kill:this.opts.killBehavior,workerId:this.id})}getMainWorker(){if(null==this.mainWorker)throw new Error("Main worker not set");return this.mainWorker}handleError(e){return e instanceof Error?e.message:e}run(e){if(this.isMain)throw new Error("Cannot run a task in the main worker");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.updateLastTaskTimestamp()}}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.updateLastTaskTimestamp()})).catch(y)}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")}updateLastTaskTimestamp(){this.isMain||null==this.activeInterval||(this.lastTaskTimestamp=r.now())}}class Y extends G{constructor(e,s={}){super("worker-cluster-pool:poolifier",t.isPrimary,t.worker,e,s)}handleReadyMessage(e){this.isMain||e.workerId!==this.id||null==e.ready||(this.getMainWorker()?.on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,workerId:this.id}))}get id(){return this.getMainWorker().id}sendToMainWorker(e){this.getMainWorker().send(e)}}class J extends G{port;constructor(e,t={}){super("worker-thread-pool:poolifier",h,c,e,t)}handleReadyMessage(e){this.isMain||e.workerId!==this.id||null==e.ready||null==e.port||(this.port=e.port,this.port.on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,workerId:this.id}))}handleKillMessage(e){super.handleKillMessage(e),this.port?.unref(),this.port?.close()}get id(){return d}sendToMainWorker(e){this.port.postMessage(e)}handleError(e){return e}}export{Y as ClusterWorker,V as DynamicClusterPool,j as DynamicThreadPool,B as FixedClusterPool,L as FixedThreadPool,R as KillBehaviors,b as Measurements,p as PoolEvents,m as PoolTypes,J as ThreadWorker,C as WorkerChoiceStrategies,D as WorkerTypes,W as availableParallelism};
@@ -1,6 +1,6 @@
1
1
  import type { MessageValue, PromiseResponseWrapper, Task } from '../utility-types';
2
2
  import { type IPool, PoolEmitter, type PoolInfo, type PoolOptions, type PoolType, type TasksQueueOptions } from './pool';
3
- import type { IWorker, IWorkerNode, WorkerType } from './worker';
3
+ import type { IWorker, IWorkerNode, WorkerInfo, WorkerType } from './worker';
4
4
  import { type WorkerChoiceStrategy, type WorkerChoiceStrategyOptions } from './selection-strategies/selection-strategies-types';
5
5
  import { WorkerChoiceStrategyContext } from './selection-strategies/worker-choice-strategy-context';
6
6
  /**
@@ -19,14 +19,14 @@ export declare abstract class AbstractPool<Worker extends IWorker, Data = unknow
19
19
  /** @inheritDoc */
20
20
  readonly emitter?: PoolEmitter;
21
21
  /**
22
- * The execution response promise map.
22
+ * The task execution response promise map.
23
23
  *
24
24
  * - `key`: The message id of each submitted task.
25
25
  * - `value`: An object that contains the worker, the execution response promise resolve and reject callbacks.
26
26
  *
27
27
  * When we receive a message from the worker, we get a map entry with the promise resolve/reject bound to the message id.
28
28
  */
29
- protected promiseResponseMap: Map<string, PromiseResponseWrapper<Worker, Response>>;
29
+ protected promiseResponseMap: Map<string, PromiseResponseWrapper<Response>>;
30
30
  /**
31
31
  * Worker choice strategy context referencing a worker choice algorithm implementation.
32
32
  */
@@ -57,38 +57,34 @@ export declare abstract class AbstractPool<Worker extends IWorker, Data = unknow
57
57
  private startPool;
58
58
  /** @inheritDoc */
59
59
  get info(): PoolInfo;
60
+ /**
61
+ * The pool readiness boolean status.
62
+ */
60
63
  private get ready();
61
64
  /**
62
- * Gets the approximate pool utilization.
65
+ * The approximate pool utilization.
63
66
  *
64
67
  * @returns The pool utilization.
65
68
  */
66
69
  private get utilization();
67
70
  /**
68
- * Pool type.
71
+ * The pool type.
69
72
  *
70
73
  * If it is `'dynamic'`, it provides the `max` property.
71
74
  */
72
75
  protected abstract get type(): PoolType;
73
76
  /**
74
- * Gets the worker type.
77
+ * The worker type.
75
78
  */
76
79
  protected abstract get worker(): WorkerType;
77
80
  /**
78
- * Pool minimum size.
81
+ * The pool minimum size.
79
82
  */
80
83
  protected abstract get minSize(): number;
81
84
  /**
82
- * Pool maximum size.
85
+ * The pool maximum size.
83
86
  */
84
87
  protected abstract get maxSize(): number;
85
- /**
86
- * Get the worker given its id.
87
- *
88
- * @param workerId - The worker id.
89
- * @returns The worker if found in the pool worker nodes, `undefined` otherwise.
90
- */
91
- private getWorkerById;
92
88
  /**
93
89
  * Checks if the worker id sent in the received message from a worker is valid.
94
90
  *
@@ -102,7 +98,14 @@ export declare abstract class AbstractPool<Worker extends IWorker, Data = unknow
102
98
  * @param worker - The worker.
103
99
  * @returns The worker node key if found in the pool worker nodes, `-1` otherwise.
104
100
  */
105
- private getWorkerNodeKey;
101
+ private getWorkerNodeKeyByWorker;
102
+ /**
103
+ * Gets the worker node key given its worker id.
104
+ *
105
+ * @param workerId - The worker id.
106
+ * @returns The worker node key if the worker id is found in the pool worker nodes, `-1` otherwise.
107
+ */
108
+ private getWorkerNodeKeyByWorkerId;
106
109
  /** @inheritDoc */
107
110
  setWorkerChoiceStrategy(workerChoiceStrategy: WorkerChoiceStrategy, workerChoiceStrategyOptions?: WorkerChoiceStrategyOptions): void;
108
111
  /** @inheritDoc */
@@ -135,11 +138,11 @@ export declare abstract class AbstractPool<Worker extends IWorker, Data = unknow
135
138
  /** @inheritDoc */
136
139
  destroy(): Promise<void>;
137
140
  /**
138
- * Terminates the given worker.
141
+ * Terminates the worker node given its worker node key.
139
142
  *
140
- * @param worker - A worker within `workerNodes`.
143
+ * @param workerNodeKey - The worker node key.
141
144
  */
142
- protected abstract destroyWorker(worker: Worker): void | Promise<void>;
145
+ protected abstract destroyWorkerNode(workerNodeKey: number): Promise<void>;
143
146
  /**
144
147
  * Setup hook to execute code before worker nodes are created in the abstract constructor.
145
148
  * Can be overridden.
@@ -163,10 +166,10 @@ export declare abstract class AbstractPool<Worker extends IWorker, Data = unknow
163
166
  * Hook executed after the worker task execution.
164
167
  * Can be overridden.
165
168
  *
166
- * @param worker - The worker.
169
+ * @param workerNodeKey - The worker node key.
167
170
  * @param message - The received message.
168
171
  */
169
- protected afterTaskExecutionHook(worker: Worker, message: MessageValue<Response>): void;
172
+ protected afterTaskExecutionHook(workerNodeKey: number, message: MessageValue<Response>): void;
170
173
  private updateTaskStatisticsWorkerUsage;
171
174
  private updateRunTimeWorkerUsage;
172
175
  private updateWaitTimeWorkerUsage;
@@ -176,7 +179,7 @@ export declare abstract class AbstractPool<Worker extends IWorker, Data = unknow
176
179
  *
177
180
  * The default worker choice strategy uses a round robin algorithm to distribute the tasks.
178
181
  *
179
- * @returns The worker node key
182
+ * @returns The chosen worker node key
180
183
  */
181
184
  private chooseWorkerNode;
182
185
  /**
@@ -186,12 +189,12 @@ export declare abstract class AbstractPool<Worker extends IWorker, Data = unknow
186
189
  */
187
190
  private shallCreateDynamicWorker;
188
191
  /**
189
- * Sends a message to the given worker.
192
+ * Sends a message to worker given its worker node key.
190
193
  *
191
- * @param worker - The worker which should receive the message.
194
+ * @param workerNodeKey - The worker node key.
192
195
  * @param message - The message.
193
196
  */
194
- protected abstract sendToWorker(worker: Worker, message: MessageValue<Data>): void;
197
+ protected abstract sendToWorker(workerNodeKey: number, message: MessageValue<Data>): void;
195
198
  /**
196
199
  * Creates a new worker.
197
200
  *
@@ -199,35 +202,46 @@ export declare abstract class AbstractPool<Worker extends IWorker, Data = unknow
199
202
  */
200
203
  protected abstract createWorker(): Worker;
201
204
  /**
202
- * Creates a new worker and sets it up completely in the pool worker nodes.
205
+ * Creates a new, completely set up worker node.
203
206
  *
204
- * @returns New, completely set up worker.
207
+ * @returns New, completely set up worker node key.
205
208
  */
206
- protected createAndSetupWorker(): Worker;
209
+ protected createAndSetupWorkerNode(): number;
207
210
  /**
208
- * Creates a new dynamic worker and sets it up completely in the pool worker nodes.
211
+ * Creates a new, completely set up dynamic worker node.
209
212
  *
210
- * @returns New, completely set up dynamic worker.
213
+ * @returns New, completely set up dynamic worker node key.
211
214
  */
212
- protected createAndSetupDynamicWorker(): Worker;
215
+ protected createAndSetupDynamicWorkerNode(): number;
213
216
  /**
214
- * Registers a listener callback on the given worker.
217
+ * Registers a listener callback on the worker given its worker node key.
215
218
  *
216
- * @param worker - The worker which should register a listener.
219
+ * @param workerNodeKey - The worker node key.
217
220
  * @param listener - The message listener callback.
218
221
  */
219
- private registerWorkerMessageListener;
222
+ protected abstract registerWorkerMessageListener<Message extends Data | Response>(workerNodeKey: number, listener: (message: MessageValue<Message>) => void): void;
220
223
  /**
221
- * Function that can be hooked up when a worker has been newly created and moved to the pool worker nodes.
224
+ * Method hooked up after a worker node has been newly created.
222
225
  * Can be overridden.
223
226
  *
224
- * @param worker - The newly created worker.
227
+ * @param workerNodeKey - The newly created worker node key.
228
+ */
229
+ protected afterWorkerNodeSetup(workerNodeKey: number): void;
230
+ /**
231
+ * Sends the startup message to worker given its worker node key.
232
+ *
233
+ * @param workerNodeKey - The worker node key.
234
+ */
235
+ protected abstract sendStartupMessageToWorker(workerNodeKey: number): void;
236
+ /**
237
+ * Sends the worker statistics message to worker given its worker node key.
238
+ *
239
+ * @param workerNodeKey - The worker node key.
225
240
  */
226
- protected afterWorkerSetup(worker: Worker): void;
227
- private sendWorkerStartupMessage;
241
+ private sendWorkerStatisticsMessageToWorker;
228
242
  private redistributeQueuedTasks;
229
243
  /**
230
- * This function is the listener registered for each worker message.
244
+ * This method is the listener registered for each worker message.
231
245
  *
232
246
  * @returns The listener function to execute when a message is received from a worker.
233
247
  */
@@ -236,16 +250,18 @@ export declare abstract class AbstractPool<Worker extends IWorker, Data = unknow
236
250
  private handleTaskExecutionResponse;
237
251
  private checkAndEmitEvents;
238
252
  /**
239
- * Gets the worker information.
253
+ * Gets the worker information given its worker node key.
240
254
  *
241
255
  * @param workerNodeKey - The worker node key.
256
+ * @returns The worker information.
242
257
  */
243
- private getWorkerInfo;
258
+ protected getWorkerInfo(workerNodeKey: number): WorkerInfo;
244
259
  /**
245
260
  * Adds the given worker in the pool worker nodes.
246
261
  *
247
262
  * @param worker - The worker.
248
- * @returns The worker nodes length.
263
+ * @returns The added worker node key.
264
+ * @throws {@link https://nodejs.org/api/errors.html#class-error} If the added worker node is not found.
249
265
  */
250
266
  private addWorkerNode;
251
267
  /**
@@ -255,16 +271,15 @@ export declare abstract class AbstractPool<Worker extends IWorker, Data = unknow
255
271
  */
256
272
  private removeWorkerNode;
257
273
  /**
258
- * Executes the given task on the given worker.
274
+ * Executes the given task on the worker given its worker node key.
259
275
  *
260
- * @param worker - The worker.
276
+ * @param workerNodeKey - The worker node key.
261
277
  * @param task - The task to execute.
262
278
  */
263
279
  private executeTask;
264
280
  private enqueueTask;
265
281
  private dequeueTask;
266
282
  private tasksQueueSize;
267
- private flushTasksQueue;
283
+ protected flushTasksQueue(workerNodeKey: number): void;
268
284
  private flushTasksQueues;
269
- private setWorkerStatistics;
270
285
  }
@@ -44,9 +44,13 @@ export declare class FixedClusterPool<Data = unknown, Response = unknown> extend
44
44
  /** @inheritDoc */
45
45
  protected isMain(): boolean;
46
46
  /** @inheritDoc */
47
- protected destroyWorker(worker: Worker): void;
47
+ protected destroyWorkerNode(workerNodeKey: number): Promise<void>;
48
48
  /** @inheritDoc */
49
- protected sendToWorker(worker: Worker, message: MessageValue<Data>): void;
49
+ protected sendToWorker(workerNodeKey: number, message: MessageValue<Data>): void;
50
+ /** @inheritDoc */
51
+ protected sendStartupMessageToWorker(workerNodeKey: number): void;
52
+ /** @inheritDoc */
53
+ protected registerWorkerMessageListener<Message extends Data | Response>(workerNodeKey: number, listener: (message: MessageValue<Message>) => void): void;
50
54
  /** @inheritDoc */
51
55
  protected createWorker(): Worker;
52
56
  /** @inheritDoc */
@@ -49,7 +49,7 @@ export interface PoolInfo {
49
49
  readonly strategy: WorkerChoiceStrategy;
50
50
  readonly minSize: number;
51
51
  readonly maxSize: number;
52
- /** Pool utilization ratio. */
52
+ /** Pool utilization. */
53
53
  readonly utilization?: number;
54
54
  /** Pool total worker nodes. */
55
55
  readonly workerNodes: number;
@@ -176,7 +176,7 @@ export interface IPool<Worker extends IWorker, Data = unknown, Response = unknow
176
176
  */
177
177
  readonly execute: (data?: Data, name?: string) => Promise<Response>;
178
178
  /**
179
- * Terminates every current worker in this pool.
179
+ * Terminates all workers in this pool.
180
180
  */
181
181
  readonly destroy: () => Promise<void>;
182
182
  /**
@@ -53,7 +53,7 @@ export declare class WorkerChoiceStrategyContext<Worker extends IWorker, Data =
53
53
  /**
54
54
  * Removes the worker node key from the worker choice strategy in the context.
55
55
  *
56
- * @param workerNodeKey - The key of the worker node.
56
+ * @param workerNodeKey - The worker node key.
57
57
  * @returns `true` if the removal is successful, `false` otherwise.
58
58
  */
59
59
  remove(workerNodeKey: number): boolean;
@@ -36,9 +36,13 @@ export declare class FixedThreadPool<Data = unknown, Response = unknown> extends
36
36
  /** @inheritDoc */
37
37
  protected isMain(): boolean;
38
38
  /** @inheritDoc */
39
- protected destroyWorker(worker: Worker): Promise<void>;
39
+ protected destroyWorkerNode(workerNodeKey: number): Promise<void>;
40
40
  /** @inheritDoc */
41
- protected sendToWorker(worker: Worker, message: MessageValue<Data>): void;
41
+ protected sendToWorker(workerNodeKey: number, message: MessageValue<Data>): void;
42
+ /** @inheritDoc */
43
+ protected sendStartupMessageToWorker(workerNodeKey: number): void;
44
+ /** @inheritDoc */
45
+ protected registerWorkerMessageListener<Message extends Data | Response>(workerNodeKey: number, listener: (message: MessageValue<Message>) => void): void;
42
46
  /** @inheritDoc */
43
47
  protected createWorker(): Worker;
44
48
  /** @inheritDoc */
@@ -1 +1 @@
1
- export declare const version = "2.6.18";
1
+ export declare const version = "2.6.20";
@@ -36,6 +36,8 @@ export declare class WorkerNode<Worker extends IWorker, Data = unknown> implemen
36
36
  /** @inheritdoc */
37
37
  resetUsage(): void;
38
38
  /** @inheritdoc */
39
+ closeChannel(): void;
40
+ /** @inheritdoc */
39
41
  getTaskWorkerUsage(name: string): WorkerUsage | undefined;
40
42
  private initWorkerInfo;
41
43
  private initWorkerUsage;
@@ -1,3 +1,5 @@
1
+ /// <reference types="node" />
2
+ import type { MessageChannel } from 'node:worker_threads';
1
3
  import type { CircularArray } from '../circular-array';
2
4
  import type { Task } from '../utility-types';
3
5
  /**
@@ -117,6 +119,10 @@ export interface WorkerInfo {
117
119
  * Ready flag.
118
120
  */
119
121
  ready: boolean;
122
+ /**
123
+ * Message channel.
124
+ */
125
+ messageChannel?: MessageChannel;
120
126
  }
121
127
  /**
122
128
  * Worker usage statistics.
@@ -212,6 +218,10 @@ export interface IWorkerNode<Worker extends IWorker, Data = unknown> {
212
218
  * Resets usage statistics .
213
219
  */
214
220
  readonly resetUsage: () => void;
221
+ /**
222
+ * Close communication channel.
223
+ */
224
+ readonly closeChannel: () => void;
215
225
  /**
216
226
  * Gets task worker usage statistics.
217
227
  */
@@ -1,7 +1,8 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  import type { EventLoopUtilization } from 'node:perf_hooks';
4
+ import type { MessagePort } from 'node:worker_threads';
3
5
  import type { KillBehavior } from './worker/worker-options';
4
- import type { IWorker } from './pools/worker';
5
6
  /**
6
7
  * Task error.
7
8
  *
@@ -113,15 +114,18 @@ export interface MessageValue<Data = unknown, ErrorData = unknown> extends Task<
113
114
  * Whether the worker starts or stops its activity check.
114
115
  */
115
116
  readonly checkActive?: boolean;
117
+ /**
118
+ * Message port.
119
+ */
120
+ readonly port?: MessagePort;
116
121
  }
117
122
  /**
118
- * An object holding the execution response promise resolve/reject callbacks.
123
+ * An object holding the task execution response promise resolve/reject callbacks.
119
124
  *
120
- * @typeParam Worker - Type of worker.
121
125
  * @typeParam Response - Type of execution response. This can only be structured-cloneable data.
122
126
  * @internal
123
127
  */
124
- export interface PromiseResponseWrapper<Worker extends IWorker, Response = unknown> {
128
+ export interface PromiseResponseWrapper<Response = unknown> {
125
129
  /**
126
130
  * Resolve callback to fulfill the promise.
127
131
  */
@@ -131,7 +135,7 @@ export interface PromiseResponseWrapper<Worker extends IWorker, Response = unkno
131
135
  */
132
136
  readonly reject: (reason?: unknown) => void;
133
137
  /**
134
- * The worker handling the execution.
138
+ * The worker node key executing the task.
135
139
  */
136
- readonly worker: Worker;
140
+ readonly workerNodeKey: number;
137
141
  }
@@ -17,7 +17,7 @@ import type { TaskFunctions, WorkerAsyncFunction, WorkerFunction, WorkerSyncFunc
17
17
  */
18
18
  export declare abstract class AbstractWorker<MainWorker extends Worker | MessagePort, Data = unknown, Response = unknown> extends AsyncResource {
19
19
  protected readonly isMain: boolean;
20
- protected readonly mainWorker: MainWorker;
20
+ private readonly mainWorker;
21
21
  protected readonly opts: WorkerOptions;
22
22
  /**
23
23
  * Worker id.
@@ -44,11 +44,11 @@ export declare abstract class AbstractWorker<MainWorker extends Worker | Message
44
44
  *
45
45
  * @param type - The type of async event.
46
46
  * @param isMain - Whether this is the main worker or not.
47
- * @param taskFunctions - Task function(s) processed by the worker when the pool's `execution` function is invoked. The first function is the default function.
48
47
  * @param mainWorker - Reference to main worker.
48
+ * @param taskFunctions - Task function(s) processed by the worker when the pool's `execution` function is invoked. The first function is the default function.
49
49
  * @param opts - Options for the worker.
50
50
  */
51
- constructor(type: string, isMain: boolean, taskFunctions: WorkerFunction<Data, Response> | TaskFunctions<Data, Response>, mainWorker: MainWorker, opts?: WorkerOptions);
51
+ constructor(type: string, isMain: boolean, mainWorker: MainWorker, taskFunctions: WorkerFunction<Data, Response> | TaskFunctions<Data, Response>, opts?: WorkerOptions);
52
52
  private checkWorkerOptions;
53
53
  /**
54
54
  * Checks if the `taskFunctions` parameter is passed to the constructor.
@@ -102,16 +102,24 @@ export declare abstract class AbstractWorker<MainWorker extends Worker | Message
102
102
  * @throws {@link https://nodejs.org/api/errors.html#class-error} If the `name` parameter is a non-existing task function.
103
103
  */
104
104
  setDefaultTaskFunction(name: string): boolean;
105
+ /**
106
+ * Handles the ready message sent by the main worker.
107
+ *
108
+ * @param message - The ready message.
109
+ */
110
+ protected abstract handleReadyMessage(message: MessageValue<Data>): void;
105
111
  /**
106
112
  * Worker message listener.
107
113
  *
108
114
  * @param message - The received message.
109
115
  */
110
- protected messageListener(message: MessageValue<Data, Data>): void;
116
+ protected messageListener(message: MessageValue<Data>): void;
111
117
  /**
112
- * Sends the ready response to the main worker.
118
+ * Handles a kill message sent by the main worker.
119
+ *
120
+ * @param message - The kill message.
113
121
  */
114
- protected sendReadyResponse(): void;
122
+ protected handleKillMessage(message: MessageValue<Data>): void;
115
123
  /**
116
124
  * Starts the worker check active interval.
117
125
  */
@@ -131,7 +139,7 @@ export declare abstract class AbstractWorker<MainWorker extends Worker | Message
131
139
  */
132
140
  protected getMainWorker(): MainWorker;
133
141
  /**
134
- * Sends a message to the main worker.
142
+ * Sends a message to main worker.
135
143
  *
136
144
  * @param message - The response message.
137
145
  */
@@ -27,6 +27,8 @@ export declare class ClusterWorker<Data = unknown, Response = unknown> extends A
27
27
  */
28
28
  constructor(taskFunctions: WorkerFunction<Data, Response> | TaskFunctions<Data, Response>, opts?: WorkerOptions);
29
29
  /** @inheritDoc */
30
+ protected handleReadyMessage(message: MessageValue<Data>): void;
31
+ /** @inheritDoc */
30
32
  protected get id(): number;
31
33
  /** @inheritDoc */
32
34
  protected sendToMainWorker(message: MessageValue<Response>): void;
@@ -19,6 +19,10 @@ import type { TaskFunctions, WorkerFunction } from './worker-functions';
19
19
  * @since 0.0.1
20
20
  */
21
21
  export declare class ThreadWorker<Data = unknown, Response = unknown> extends AbstractWorker<MessagePort, Data, Response> {
22
+ /**
23
+ * Message port used to communicate with the main worker.
24
+ */
25
+ private port;
22
26
  /**
23
27
  * Constructs a new poolifier thread worker.
24
28
  *
@@ -26,6 +30,11 @@ export declare class ThreadWorker<Data = unknown, Response = unknown> extends Ab
26
30
  * @param opts - Options for the worker.
27
31
  */
28
32
  constructor(taskFunctions: WorkerFunction<Data, Response> | TaskFunctions<Data, Response>, opts?: WorkerOptions);
33
+ /** @inheritDoc */
34
+ protected handleReadyMessage(message: MessageValue<Data>): void;
35
+ /** @inheritDoc */
36
+ protected handleKillMessage(message: MessageValue<Data, unknown>): void;
37
+ /** @inheritDoc */
29
38
  protected get id(): number;
30
39
  /** @inheritDoc */
31
40
  protected sendToMainWorker(message: MessageValue<Response>): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poolifier",
3
- "version": "2.6.18",
3
+ "version": "2.6.20",
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",
@@ -25,7 +25,7 @@
25
25
  "pnpm": ">=8.6.0"
26
26
  },
27
27
  "volta": {
28
- "node": "20.4.0",
28
+ "node": "20.5.0",
29
29
  "pnpm": "8.6.9"
30
30
  },
31
31
  "repository": {
@@ -106,7 +106,7 @@
106
106
  "mocha": "^10.2.0",
107
107
  "mochawesome": "^7.1.3",
108
108
  "prettier": "^3.0.0",
109
- "release-it": "^16.1.2",
109
+ "release-it": "^16.1.3",
110
110
  "rollup": "^3.26.3",
111
111
  "rollup-plugin-analyzer": "^4.0.0",
112
112
  "rollup-plugin-command": "^1.1.3",