poolifier 4.0.3 → 4.0.4
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.cjs +1 -1
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.ts +8 -3
- package/lib/index.mjs +1 -1
- package/lib/index.mjs.map +1 -1
- package/package.json +2 -2
package/lib/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e,{Worker as t}from"node:cluster";import{existsSync as r}from"node:fs";import{env as s}from"node:process";import{Worker as i,SHARE_ENV as o,MessageChannel as n,isMainThread as a,parentPort as u,threadId as h}from"node:worker_threads";import{getRandomValues as k,randomUUID as c}from"node:crypto";import*as d from"node:os";import{cpus as l}from"node:os";import{AsyncResource as g}from"node:async_hooks";import{EventEmitter as m,EventEmitterAsyncResource as p}from"node:events";import{performance as w}from"node:perf_hooks";const y=Object.freeze({fixed:"fixed",dynamic:"dynamic"}),f=Object.freeze({ready:"ready",busy:"busy",full:"full",empty:"empty",destroy:"destroy",error:"error",taskError:"taskError",backPressure:"backPressure"}),T="default",W=Object.freeze((()=>{})),N=()=>{let e=1;try{e=d.availableParallelism()}catch{const t=d.cpus();Array.isArray(t)&&t.length>0&&(e=t.length)}return e},S=e=>Array.isArray(e)&&0===e.length?0:Array.isArray(e)&&1===e.length?e[0]:e.reduce(((e,t)=>e+t),0)/e.length,E=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},v=(e,t=2)=>{const r=Math.pow(10,t);return Math.round(e*r*(1+Number.EPSILON))/r},x=e=>"object"==typeof e&&null!==e&&e.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),C=(e,t)=>t===e,b=e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name,F=()=>k(new Uint32Array(1))[0]/4294967296,O=(...e)=>e.reduce(((e,t)=>e<t?e:t),1/0),I=(...e)=>e.reduce(((e,t)=>e>t?e:t),-1/0),P=(e,t)=>({name:e,...null!=t?.priority&&{priority:t.priority},...null!=t?.strategy&&{strategy:t.strategy}}),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"}),z=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"}),M=Object.freeze({thread:"thread",cluster:"cluster"}),q={aggregate:!1,average:!1,median:!1},K=e=>({size:Math.pow(e,2),concurrency:1,taskStealing:!0,tasksStealingOnBackPressure:!0,tasksFinishedTimeout:2e3}),A=e=>{if(null==e)throw new TypeError("The worker file path must be specified");if("string"!=typeof e)throw new TypeError("The worker file path must be a string");if(!r(e))throw new Error(`Cannot find the worker file '${e}'`)},Q=(e,t)=>{if(null==t)throw new TypeError("Cannot instantiate a dynamic pool without specifying the maximum pool size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot instantiate a dynamic pool with a non safe integer maximum pool size");if(e>t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size");if(0===t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size equal to zero");if(e===t)throw new RangeError("Cannot instantiate a dynamic pool with a minimum pool size equal to the maximum pool size. Use a fixed pool instead")},U=e=>{if(null!=e&&!Number.isSafeInteger(e))throw new TypeError(`Invalid property 'priority': '${e}'`);if(null!=e&&Number.isSafeInteger(e)&&(e<-20||e>19))throw new RangeError("Property 'priority' must be between -20 and 19")},B=e=>{if(null!=e&&!Object.values(R).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)},D=e=>{if(null!=e&&!x(e))throw new TypeError("Invalid tasks queue options: must be a plain object");if(null!=e?.concurrency&&!Number.isSafeInteger(e.concurrency))throw new TypeError("Invalid worker node tasks concurrency: must be an integer");if(null!=e?.concurrency&&e.concurrency<=0)throw new RangeError(`Invalid worker node tasks concurrency: ${e.concurrency} is a negative integer or zero`);if(null!=e?.size&&!Number.isSafeInteger(e.size))throw new TypeError("Invalid worker node tasks queue size: must be an integer");if(null!=e?.size&&e.size<=0)throw new RangeError(`Invalid worker node tasks queue size: ${e.size} is a negative integer or zero`)},L=(e,t,r)=>{null!=t&&null!=r&&t.aggregate&&(e.aggregate=(e.aggregate??0)+r,e.minimum=O(r,e.minimum??1/0),e.maximum=I(r,e.maximum??-1/0),(t.average||t.median)&&(e.history.push(r),t.average?e.average=S(e.history):null!=e.average&&delete e.average,t.median?e.median=E(e.history):null!=e.median&&delete e.median))};"test"===s.NODE_ENV&&(exports.updateMeasurementStatistics=L);const H=(e,t,r)=>{const s=performance.now(),i=s-(r.timestamp??s);L(t.waitTime,e?.getTaskStatisticsRequirements().waitTime,i)},_=(e,t)=>{const r=e.tasks;null!=r.executing&&r.executing>0&&--r.executing,null==t.workerError?++r.executed:++r.failed},$=(e,t,r)=>{null==r.workerError&&L(t.runTime,e?.getTaskStatisticsRequirements().runTime,r.taskPerformance?.runTime??0)},j=(e,t,r)=>{if(null!=r.workerError)return;const s=e?.getTaskStatisticsRequirements().elu;L(t.elu.active,s,r.taskPerformance?.elu?.active??0),L(t.elu.idle,s,r.taskPerformance?.elu?.idle??0),!0===s?.aggregate&&null!=r.taskPerformance?.elu&&(null!=t.elu.utilization?t.elu.utilization=(t.elu.utilization+r.taskPerformance.elu.utilization)/2:t.elu.utilization=r.taskPerformance.elu.utilization)},V=e=>e instanceof i?M.thread:e instanceof t?M.cluster:void 0,G=e=>e instanceof i?e.threadId:e instanceof t?e.id:void 0,Y=Object.freeze({SOFT:"SOFT",HARD:"HARD"});class J{pool;opts;nextWorkerNodeKey=0;previousWorkerNodeKey=0;strategyPolicy={dynamicWorkerUsage:!1,dynamicWorkerReady:!0};taskStatisticsRequirements={runTime:q,waitTime:q,elu:q};constructor(e,t){this.pool=e,this.opts=t,this.choose=this.choose.bind(this),this.setOptions(this.opts)}setTaskStatisticsRequirements(e){ue(this.taskStatisticsRequirements.runTime,e.runTime.median),ue(this.taskStatisticsRequirements.waitTime,e.waitTime.median),ue(this.taskStatisticsRequirements.elu,e.elu.median)}resetWorkerNodeKeyProperties(){this.nextWorkerNodeKey=0,this.previousWorkerNodeKey=0}setOptions(e){this.opts=ae(this.pool,e),this.setTaskStatisticsRequirements(this.opts)}isWorkerNodeReady(e){return this.pool.workerNodes[e]?.info?.ready??!1}checkNextWorkerNodeKey(){null!=this.nextWorkerNodeKey&&(this.nextWorkerNodeKey<0||!this.isWorkerNodeReady(this.nextWorkerNodeKey))&&delete this.nextWorkerNodeKey}getWorkerNodeTaskRunTime(e){return this.taskStatisticsRequirements.runTime.median?this.pool.workerNodes[e].usage.runTime.median??0:this.pool.workerNodes[e].usage.runTime.average??0}getWorkerNodeTaskWaitTime(e){return this.taskStatisticsRequirements.waitTime.median?this.pool.workerNodes[e].usage.waitTime.median??0:this.pool.workerNodes[e].usage.waitTime.average??0}getWorkerNodeTaskElu(e){return this.taskStatisticsRequirements.elu.median?this.pool.workerNodes[e].usage.elu.active.median??0:this.pool.workerNodes[e].usage.elu.active.average??0}setPreviousWorkerNodeKey(e){this.previousWorkerNodeKey=null!=e&&e>=0?e:this.previousWorkerNodeKey}}class X extends J{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:{aggregate:!0,average:!0,median:!1},elu:{aggregate:!0,average:!0,median:!1}};constructor(e,t){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){for(const e of this.pool.workerNodes)delete e.strategyData?.virtualTaskEndTimestamp;return!0}update(e){return this.pool.workerNodes[e].strategyData={virtualTaskEndTimestamp:this.computeWorkerNodeVirtualTaskEndTimestamp(e)},!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.fairShareNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}fairShareNextWorkerNodeKey(){if(0!==this.pool.workerNodes.length)return this.pool.workerNodes.reduce(((e,t,r,s)=>(null==t.strategyData?.virtualTaskEndTimestamp&&(t.strategyData={virtualTaskEndTimestamp:this.computeWorkerNodeVirtualTaskEndTimestamp(r)}),this.isWorkerNodeReady(r)&&t.strategyData.virtualTaskEndTimestamp<s[e].strategyData.virtualTaskEndTimestamp?r:e)),0)}computeWorkerNodeVirtualTaskEndTimestamp(e){return this.getWorkerNodeVirtualTaskEndTimestamp(e,this.getWorkerNodeVirtualTaskStartTimestamp(e))}getWorkerNodeVirtualTaskEndTimestamp(e,t){return t+(this.getWorkerNodeTaskWaitTime(e)+(this.opts.measurement===z.elu?this.getWorkerNodeTaskElu(e):this.getWorkerNodeTaskRunTime(e)))}getWorkerNodeVirtualTaskStartTimestamp(e){const t=this.pool.workerNodes[e]?.strategyData?.virtualTaskEndTimestamp,r=performance.now();return r<(t??-1/0)?t:r}}class Z extends J{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:{aggregate:!0,average:!0,median:!1},elu:q};roundId=0;roundWeights;workerNodeId=0;workerNodeVirtualTaskExecutionTime=0;constructor(e,t){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.roundWeights=this.getRoundWeights()}reset(){return this.resetWorkerNodeKeyProperties(),this.roundId=0,this.workerNodeId=0,this.workerNodeVirtualTaskExecutionTime=0,!0}update(){return!0}choose(){for(let e=this.roundId;e<this.roundWeights.length;e++){this.roundId=e;for(let t=this.workerNodeId;t<this.pool.workerNodes.length;t++){this.workerNodeId=t,this.workerNodeId!==this.nextWorkerNodeKey&&0!==this.workerNodeVirtualTaskExecutionTime&&(this.workerNodeVirtualTaskExecutionTime=0);const r=this.opts.weights[t];if(this.isWorkerNodeReady(t)&&r>=this.roundWeights[e]&&this.workerNodeVirtualTaskExecutionTime<r)return this.workerNodeVirtualTaskExecutionTime+=this.getWorkerNodeTaskWaitTime(t)+this.getWorkerNodeTaskRunTime(t),this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=t,this.nextWorkerNodeKey}}this.interleavedWeightedRoundRobinNextWorkerNodeId()}interleavedWeightedRoundRobinNextWorkerNodeId(){0===this.pool.workerNodes.length?this.workerNodeId=0:this.roundId===this.roundWeights.length-1&&this.workerNodeId===this.pool.workerNodes.length-1?(this.roundId=0,this.workerNodeId=0):this.workerNodeId===this.pool.workerNodes.length-1?(this.roundId=this.roundId+1,this.workerNodeId=0):this.workerNodeId=this.workerNodeId+1}remove(e){return 0===this.pool.workerNodes.length?(this.resetWorkerNodeKeyProperties(),this.workerNodeId=0,this.workerNodeVirtualTaskExecutionTime=0,!0):(this.workerNodeId===e&&this.workerNodeId>this.pool.workerNodes.length-1&&(this.workerNodeId=this.pool.workerNodes.length-1),this.previousWorkerNodeKey===e&&this.previousWorkerNodeKey>this.pool.workerNodes.length-1&&(this.previousWorkerNodeKey=this.pool.workerNodes.length-1),!0)}setOptions(e){super.setOptions(e),this.roundWeights=this.getRoundWeights()}getRoundWeights(){return[...new Set(Object.values(this.opts.weights).slice().sort(((e,t)=>e-t)))]}}class ee extends J{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:q};constructor(e,t){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastBusyNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastBusyNextWorkerNodeKey(){if(0!==this.pool.workerNodes.length)return this.pool.workerNodes.reduce(((e,t,r,s)=>this.isWorkerNodeReady(r)&&(t.usage.waitTime.aggregate??0)+(t.usage.runTime.aggregate??0)<(s[e].usage.waitTime.aggregate??0)+(s[e].usage.runTime.aggregate??0)?r:e),0)}}class te extends J{taskStatisticsRequirements={runTime:q,waitTime:q,elu:{aggregate:!0,average:!1,median:!1}};constructor(e,t){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastEluNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastEluNextWorkerNodeKey(){if(0!==this.pool.workerNodes.length)return this.pool.workerNodes.reduce(((e,t,r,s)=>this.isWorkerNodeReady(r)&&(t.usage.elu.active.aggregate??0)<(s[e].usage.elu.active.aggregate??0)?r:e),0)}}class re extends J{constructor(e,t){super(e,t)}reset(){return!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastUsedNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastUsedNextWorkerNodeKey(){if(0!==this.pool.workerNodes.length)return this.pool.workerNodes.reduce(((e,t,r,s)=>this.isWorkerNodeReady(r)&&t.usage.tasks.executing+t.usage.tasks.queued<s[e].usage.tasks.executing+s[e].usage.tasks.queued?r:e),0)}}class se extends J{constructor(e,t){super(e,t)}reset(){return this.resetWorkerNodeKeyProperties(),!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;return this.setPreviousWorkerNodeKey(e),this.roundRobinNextWorkerNodeKey(),this.checkNextWorkerNodeKey(),e}remove(e){return 0===this.pool.workerNodes.length?(this.reset(),!0):(this.nextWorkerNodeKey===e&&this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1),this.previousWorkerNodeKey===e&&this.previousWorkerNodeKey>this.pool.workerNodes.length-1&&(this.previousWorkerNodeKey=this.pool.workerNodes.length-1),!0)}roundRobinNextWorkerNodeKey(){return this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,this.nextWorkerNodeKey}}class ie extends J{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:{aggregate:!0,average:!0,median:!1},elu:q};workerNodeVirtualTaskExecutionTime=0;constructor(e,t){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.resetWorkerNodeKeyProperties(),this.workerNodeVirtualTaskExecutionTime=0,!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.weightedRoundRobinNextWorkerNodeKey(),this.checkNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(e){return 0===this.pool.workerNodes.length?(this.reset(),!0):(this.nextWorkerNodeKey===e&&(this.workerNodeVirtualTaskExecutionTime=0,this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1)),this.previousWorkerNodeKey===e&&this.previousWorkerNodeKey>this.pool.workerNodes.length-1&&(this.previousWorkerNodeKey=this.pool.workerNodes.length-1),!0)}weightedRoundRobinNextWorkerNodeKey(){const e=this.opts.weights[this.nextWorkerNodeKey??this.previousWorkerNodeKey];return this.workerNodeVirtualTaskExecutionTime<e?this.workerNodeVirtualTaskExecutionTime+=this.getWorkerNodeTaskWaitTime(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+this.getWorkerNodeTaskRunTime(this.nextWorkerNodeKey??this.previousWorkerNodeKey):(this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,this.workerNodeVirtualTaskExecutionTime=0),this.nextWorkerNodeKey}}const oe=()=>{const e=l();let t;e.every((e=>null==e.speed||0===e.speed))&&(t=(()=>{const e=performance.now(),t=performance.now()-e;return Math.trunc(15e7/t/1e3)})());let r=0;for(const s of e){null!=s.speed&&0!==s.speed||(s.speed=e.find((e=>null!=e.speed&&0!==e.speed))?.speed??t??2e3);const i=s.speed.toString().length-1;r+=1/(s.speed/Math.pow(10,i))*Math.pow(10,i)}return Math.round(r/e.length)},ne=(e,t)=>{t=t??oe();const r={};for(let s=0;s<e;s++)r[s]=t;return r},ae=(e,t)=>((t=structuredClone(t??{})).weights=t.weights??ne(e.info.maxSize),{runTime:{median:!1},waitTime:{median:!1},elu:{median:!1},...t}),ue=(e,t)=>{e.average&&t&&(e.average=!1,e.median=t),e.median&&!t&&(e.average=!0,e.median=t)},he=e=>{const t=[];for(const r of e.values())t.push(r.strategyPolicy);return{dynamicWorkerUsage:t.some((e=>e.dynamicWorkerUsage)),dynamicWorkerReady:t.some((e=>e.dynamicWorkerReady))}},ke=e=>{const t=[];for(const r of e.values())t.push(r.taskStatisticsRequirements);return{runTime:{aggregate:t.some((e=>e.runTime.aggregate)),average:t.some((e=>e.runTime.average)),median:t.some((e=>e.runTime.median))},waitTime:{aggregate:t.some((e=>e.waitTime.aggregate)),average:t.some((e=>e.waitTime.average)),median:t.some((e=>e.waitTime.median))},elu:{aggregate:t.some((e=>e.elu.aggregate)),average:t.some((e=>e.elu.average)),median:t.some((e=>e.elu.median))}}};class ce{pool;retriesCount;defaultWorkerChoiceStrategy;workerChoiceStrategies;workerChoiceStrategiesPolicy;workerChoiceStrategiesTaskStatisticsRequirements;retries;constructor(e,t=[R.ROUND_ROBIN],r){this.pool=e,this.execute=this.execute.bind(this),this.defaultWorkerChoiceStrategy=t[0],this.workerChoiceStrategies=new Map;for(const e of t)this.addWorkerChoiceStrategy(e,this.pool,r);this.workerChoiceStrategiesPolicy=he(this.workerChoiceStrategies),this.workerChoiceStrategiesTaskStatisticsRequirements=ke(this.workerChoiceStrategies),this.retriesCount=0,this.retries=((e,t)=>e.info.maxSize+Object.keys(t?.weights??ne(e.info.maxSize)).length)(this.pool,r)}getPolicy(){return this.workerChoiceStrategiesPolicy}getTaskStatisticsRequirements(){return this.workerChoiceStrategiesTaskStatisticsRequirements}setDefaultWorkerChoiceStrategy(e,t){e!==this.defaultWorkerChoiceStrategy&&(this.defaultWorkerChoiceStrategy=e,this.addWorkerChoiceStrategy(e,this.pool,t))}update(e){const t=[];for(const r of this.workerChoiceStrategies.values())t.push(r.update(e));return t.every((e=>e))}execute(e=this.defaultWorkerChoiceStrategy){return this.executeStrategy(this.workerChoiceStrategies.get(e))}executeStrategy(e){let t,r=0,s=0;do{t=e.choose(),null==t&&r>0&&(++s,++this.retriesCount),++r}while(null==t&&s<this.retries);if(null==t)throw new Error(`Worker node key chosen is null or undefined after ${s} retries`);return t}remove(e){const t=[];for(const r of this.workerChoiceStrategies.values())t.push(r.remove(e));return t.every((e=>e))}setOptions(e){for(const t of this.workerChoiceStrategies.values())t.setOptions(e)}syncWorkerChoiceStrategies(e,t){for(const t of this.workerChoiceStrategies.keys())e.has(t)||this.removeWorkerChoiceStrategy(t);for(const r of e)this.workerChoiceStrategies.has(r)||this.addWorkerChoiceStrategy(r,this.pool,t);this.workerChoiceStrategiesPolicy=he(this.workerChoiceStrategies),this.workerChoiceStrategiesTaskStatisticsRequirements=ke(this.workerChoiceStrategies)}addWorkerChoiceStrategy(e,t,r){return this.workerChoiceStrategies.has(e)?this.workerChoiceStrategies:this.workerChoiceStrategies.set(e,((e,t,r,s)=>{switch(e){case R.ROUND_ROBIN:return new(se.bind(r))(t,s);case R.LEAST_USED:return new(re.bind(r))(t,s);case R.LEAST_BUSY:return new(ee.bind(r))(t,s);case R.LEAST_ELU:return new(te.bind(r))(t,s);case R.FAIR_SHARE:return new(X.bind(r))(t,s);case R.WEIGHTED_ROUND_ROBIN:return new(ie.bind(r))(t,s);case R.INTERLEAVED_WEIGHTED_ROUND_ROBIN:return new(Z.bind(r))(t,s);default:throw new Error(`Worker choice strategy '${e}' is not valid`)}})(e,t,this,r))}removeWorkerChoiceStrategy(e){return this.workerChoiceStrategies.delete(e)}}class de extends Array{size;constructor(e=385,...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=[];if(arguments.length>=3&&null!=t){if(s=super.splice(e,t,...r),this.length>this.size){const e=super.splice(0,this.length-this.size);s=new de(s.length+e.length,...s,...e)}}else s=2===arguments.length?super.splice(e,t):super.splice(e);return 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 le{nodeArray;k;size;maxSize;get buckets(){return this.k===1/0?1:Math.trunc(this.nodeArray.length/this.k)}constructor(e=1/0){if(e!==1/0&&!Number.isSafeInteger(e))throw new TypeError("k must be an integer");if(e<1)throw new RangeError("k must be greater than or equal to 1");this.k=e,this.clear()}enqueue(e,t){t=t??0;let r=!1;for(let s=this.k===1/0?0:this.buckets*this.k;s<this.nodeArray.length;s++)if(this.nodeArray[s].priority>t){this.nodeArray.splice(s,0,{data:e,priority:t}),r=!0;break}return r||this.nodeArray.push({data:e,priority:t}),this.incrementSize()}dequeue(e=0){if(this.k!==1/0&&e>0)for(;e>0;){const t=e*this.k;if(null!=this.nodeArray[t])return--this.size,this.nodeArray.splice(t,1)[0].data;--e}return this.size>0&&--this.size,this.nodeArray.shift()?.data}peekFirst(){return this.nodeArray[0]?.data}peekLast(){return this.nodeArray[this.nodeArray.length-1]?.data}clear(){this.nodeArray=[],this.size=0,this.maxSize=0}[Symbol.iterator](){let e=0;return{next:()=>{if(e>=this.nodeArray.length)return{value:void 0,done:!0};const t=this.nodeArray[e].data;return e++,{value:t,done:!1}}}}incrementSize(){return++this.size,this.size>this.maxSize&&(this.maxSize=this.size),this.size}}class ge extends m{worker;info;usage;strategyData;messageChannel;tasksQueueBackPressureSize;tasksQueue;onBackPressureStarted;taskFunctionsUsage;constructor(t,r,s){super(),((e,t,r)=>{if(null==e)throw new TypeError("Cannot construct a worker node without a worker type");if(!Object.values(M).includes(e))throw new TypeError(`Cannot construct a worker node with an invalid worker type '${e}'`);if(A(t),null==r)throw new TypeError("Cannot construct a worker node without worker node options");if(!x(r))throw new TypeError("Cannot construct a worker node with invalid options: must be a plain object");if(null==r.tasksQueueBackPressureSize)throw new TypeError("Cannot construct a worker node without a tasks queue back pressure size option");if(!Number.isSafeInteger(r.tasksQueueBackPressureSize))throw new TypeError("Cannot construct a worker node with a tasks queue back pressure size option that is not an integer");if(r.tasksQueueBackPressureSize<=0)throw new RangeError("Cannot construct a worker node with a tasks queue back pressure size option that is not a positive integer");if(null==r.tasksQueueBucketSize)throw new TypeError("Cannot construct a worker node without a tasks queue bucket size option");if(!Number.isSafeInteger(r.tasksQueueBucketSize))throw new TypeError("Cannot construct a worker node with a tasks queue bucket size option that is not an integer");if(r.tasksQueueBucketSize<=0)throw new RangeError("Cannot construct a worker node with a tasks queue bucket size option that is not a positive integer")})(t,r,s),this.worker=((t,r,s)=>{switch(t){case M.thread:return new i(r,{env:o,...s.workerOptions});case M.cluster:return e.fork(s.env);default:throw new Error(`Unknown worker type '${t}'`)}})(t,r,{env:s.env,workerOptions:s.workerOptions}),this.info=this.initWorkerInfo(this.worker),this.usage=this.initWorkerUsage(),this.info.type===M.thread&&(this.messageChannel=new n),this.tasksQueueBackPressureSize=s.tasksQueueBackPressureSize,this.tasksQueue=new le(s.tasksQueueBucketSize),this.onBackPressureStarted=!1,this.taskFunctionsUsage=new Map}tasksQueueSize(){return this.tasksQueue.size}enqueueTask(e){const t=this.tasksQueue.enqueue(e,e.priority);return this.hasBackPressure()&&!this.onBackPressureStarted&&(this.onBackPressureStarted=!0,this.emit("backPressure",{workerId:this.info.id}),this.onBackPressureStarted=!1),t}dequeueTask(e){return this.tasksQueue.dequeue(e)}dequeueLastBucketTask(){return this.tasksQueue.dequeue(this.tasksQueue.buckets+1)}clearTasksQueue(){this.tasksQueue.clear()}hasBackPressure(){return this.tasksQueue.size>=this.tasksQueueBackPressureSize}async terminate(){const e=new Promise((e=>{this.registerOnceWorkerEventHandler("exit",(()=>{e()}))}));switch(this.closeMessageChannel(),this.removeAllListeners(),this.info.type){case M.thread:this.worker.unref?.(),await(this.worker.terminate?.());break;case M.cluster:this.registerOnceWorkerEventHandler("disconnect",(()=>{this.worker.kill?.()})),this.worker.disconnect?.()}await e}registerWorkerEventHandler(e,t){this.worker.on(e,t)}registerOnceWorkerEventHandler(e,t){this.worker.once(e,t)}getTaskFunctionWorkerUsage(e){if(!Array.isArray(this.info.taskFunctionsProperties))throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function properties list is not yet defined`);if(Array.isArray(this.info.taskFunctionsProperties)&&this.info.taskFunctionsProperties.length<3)throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function properties list has less than 3 elements`);return e===T&&(e=this.info.taskFunctionsProperties[1].name),this.taskFunctionsUsage.has(e)||this.taskFunctionsUsage.set(e,this.initTaskFunctionWorkerUsage(e)),this.taskFunctionsUsage.get(e)}deleteTaskFunctionWorkerUsage(e){return this.taskFunctionsUsage.delete(e)}closeMessageChannel(){null!=this.messageChannel&&(this.messageChannel.port1.unref(),this.messageChannel.port2.unref(),this.messageChannel.port1.close(),this.messageChannel.port2.close(),delete this.messageChannel)}initWorkerInfo(e){return{id:G(e),type:V(e),dynamic:!1,ready:!1,stealing:!1}}initWorkerUsage(){const e=()=>this.tasksQueue.size,t=()=>this.tasksQueue.maxSize;return{tasks:{executed:0,executing:0,get queued(){return e()},get maxQueued(){return t()},sequentiallyStolen:0,stolen:0,failed:0},runTime:{history:new de},waitTime:{history:new de},elu:{idle:{history:new de},active:{history:new de}}}}initTaskFunctionWorkerUsage(e){const t=()=>{let t=0;for(const r of this.tasksQueue)(r.name===T&&e===this.info.taskFunctionsProperties[1].name||r.name!==T&&e===r.name)&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},sequentiallyStolen:0,stolen:0,failed:0},runTime:{history:new de},waitTime:{history:new de},elu:{idle:{history:new de},active:{history:new de}}}}}class me{minimumNumberOfWorkers;filePath;opts;maximumNumberOfWorkers;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategiesContext;taskFunctions;started;starting;destroying;startingMinimumNumberOfWorkers;readyEventEmitted;startTimestamp;constructor(e,t,r,s){if(this.minimumNumberOfWorkers=e,this.filePath=t,this.opts=r,this.maximumNumberOfWorkers=s,!this.isMain())throw new Error("Cannot start a pool from a worker with the same type as the pool");this.checkPoolType(),A(this.filePath),this.checkMinimumNumberOfWorkers(this.minimumNumberOfWorkers),this.checkPoolOptions(this.opts),this.chooseWorkerNode=this.chooseWorkerNode.bind(this),this.executeTask=this.executeTask.bind(this),this.enqueueTask=this.enqueueTask.bind(this),!0===this.opts.enableEvents&&this.initEventEmitter(),this.workerChoiceStrategiesContext=new ce(this,[this.opts.workerChoiceStrategy],this.opts.workerChoiceStrategyOptions),this.setupHook(),this.taskFunctions=new Map,this.started=!1,this.starting=!1,this.destroying=!1,this.readyEventEmitted=!1,this.startingMinimumNumberOfWorkers=!1,!0===this.opts.startWorkers&&this.start()}checkPoolType(){if(this.type===y.fixed&&null!=this.maximumNumberOfWorkers)throw new Error("Cannot instantiate a fixed pool with a maximum number of workers specified at initialization")}checkMinimumNumberOfWorkers(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===y.fixed&&0===e)throw new RangeError("Cannot instantiate a fixed pool with zero worker")}checkPoolOptions(e){if(!x(e))throw new TypeError("Invalid pool options: must be a plain object");this.opts.startWorkers=e.startWorkers??!0,B(e.workerChoiceStrategy),this.opts.workerChoiceStrategy=e.workerChoiceStrategy??R.ROUND_ROBIN,this.checkValidWorkerChoiceStrategyOptions(e.workerChoiceStrategyOptions),null!=e.workerChoiceStrategyOptions&&(this.opts.workerChoiceStrategyOptions=e.workerChoiceStrategyOptions),this.opts.restartWorkerOnError=e.restartWorkerOnError??!0,this.opts.enableEvents=e.enableEvents??!0,this.opts.enableTasksQueue=e.enableTasksQueue??!1,this.opts.enableTasksQueue&&(D(e.tasksQueueOptions),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e.tasksQueueOptions))}checkValidWorkerChoiceStrategyOptions(e){if(null!=e&&!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.maximumNumberOfWorkers??this.minimumNumberOfWorkers))throw new Error("Invalid worker choice strategy options: must have a weight for each worker node");if(null!=e?.measurement&&!Object.values(z).includes(e.measurement))throw new Error(`Invalid worker choice strategy options: invalid measurement '${e.measurement}'`)}initEventEmitter(){this.emitter=new p({name:`poolifier:${this.type}-${this.worker}-pool`})}get info(){return{version:"4.0.3",type:this.type,worker:this.worker,started:this.started,ready:this.ready,defaultStrategy:this.opts.workerChoiceStrategy,strategyRetries:this.workerChoiceStrategiesContext?.retriesCount??0,minSize:this.minimumNumberOfWorkers,maxSize:this.maximumNumberOfWorkers??this.minimumNumberOfWorkers,...!0===this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements().runTime.aggregate&&this.workerChoiceStrategiesContext.getTaskStatisticsRequirements().waitTime.aggregate&&{utilization:v(this.utilization)},workerNodes:this.workerNodes.length,idleWorkerNodes:this.workerNodes.reduce(((e,t)=>0===t.usage.tasks.executing?e+1:e),0),...!0===this.opts.enableTasksQueue&&{stealingWorkerNodes:this.workerNodes.reduce(((e,t)=>t.info.stealing?e+1:e),0)},busyWorkerNodes:this.workerNodes.reduce(((e,t,r)=>this.isWorkerNodeBusy(r)?e+1:e),0),executedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executed),0),executingTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executing),0),...!0===this.opts.enableTasksQueue&&{queuedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.queued),0)},...!0===this.opts.enableTasksQueue&&{maxQueuedTasks:this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks.maxQueued??0)),0)},...!0===this.opts.enableTasksQueue&&{backPressure:this.hasBackPressure()},...!0===this.opts.enableTasksQueue&&{stolenTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.stolen),0)},failedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.failed),0),...!0===this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements().runTime.aggregate&&{runTime:{minimum:v(O(...this.workerNodes.map((e=>e.usage.runTime.minimum??1/0)))),maximum:v(I(...this.workerNodes.map((e=>e.usage.runTime.maximum??-1/0)))),...this.workerChoiceStrategiesContext.getTaskStatisticsRequirements().runTime.average&&{average:v(S(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))},...this.workerChoiceStrategiesContext.getTaskStatisticsRequirements().runTime.median&&{median:v(E(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))}}},...!0===this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:v(O(...this.workerNodes.map((e=>e.usage.waitTime.minimum??1/0)))),maximum:v(I(...this.workerNodes.map((e=>e.usage.waitTime.maximum??-1/0)))),...this.workerChoiceStrategiesContext.getTaskStatisticsRequirements().waitTime.average&&{average:v(S(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.waitTime.history)),[])))},...this.workerChoiceStrategiesContext.getTaskStatisticsRequirements().waitTime.median&&{median:v(E(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.waitTime.history)),[])))}}}}}get ready(){return!this.empty&&this.workerNodes.reduce(((e,t)=>!t.info.dynamic&&t.info.ready?e+1:e),0)>=this.minimumNumberOfWorkers}get empty(){return 0===this.minimumNumberOfWorkers&&0===this.workerNodes.length}get utilization(){if(null==this.startTimestamp)return 0;const e=(w.now()-this.startTimestamp)*(this.maximumNumberOfWorkers??this.minimumNumberOfWorkers);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)throw new Error("Worker message received without worker id");if(-1===this.getWorkerNodeKeyByWorkerId(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKeyByWorkerId(e){return this.workerNodes.findIndex((t=>t.info.id===e))}setWorkerChoiceStrategy(e,t){let r=!1;if(B(e),null!=t&&(r=!this.setWorkerChoiceStrategyOptions(t)),e!==this.opts.workerChoiceStrategy&&(this.opts.workerChoiceStrategy=e,this.workerChoiceStrategiesContext?.setDefaultWorkerChoiceStrategy(this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),r=!0),r){this.workerChoiceStrategiesContext?.syncWorkerChoiceStrategies(this.getWorkerWorkerChoiceStrategies(),this.opts.workerChoiceStrategyOptions);for(const e of this.workerNodes.keys())this.sendStatisticsMessageToWorker(e)}}setWorkerChoiceStrategyOptions(e){if(this.checkValidWorkerChoiceStrategyOptions(e),null!=e){this.opts.workerChoiceStrategyOptions=e,this.workerChoiceStrategiesContext?.setOptions(this.opts.workerChoiceStrategyOptions),this.workerChoiceStrategiesContext?.syncWorkerChoiceStrategies(this.getWorkerWorkerChoiceStrategies(),this.opts.workerChoiceStrategyOptions);for(const e of this.workerNodes.keys())this.sendStatisticsMessageToWorker(e);return!0}return!1}enableTasksQueue(e,t){!0!==this.opts.enableTasksQueue||e||(this.unsetTaskStealing(),this.unsetTasksStealingOnBackPressure(),this.flushTasksQueues()),this.opts.enableTasksQueue=e,this.setTasksQueueOptions(t)}setTasksQueueOptions(e){!0===this.opts.enableTasksQueue?(D(e),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e),this.setTasksQueueSize(this.opts.tasksQueueOptions.size),!0===this.opts.tasksQueueOptions.taskStealing?(this.unsetTaskStealing(),this.setTaskStealing()):this.unsetTaskStealing(),!0===this.opts.tasksQueueOptions.tasksStealingOnBackPressure?(this.unsetTasksStealingOnBackPressure(),this.setTasksStealingOnBackPressure()):this.unsetTasksStealingOnBackPressure()):null!=this.opts.tasksQueueOptions&&delete this.opts.tasksQueueOptions}buildTasksQueueOptions(e){return{...K(this.maximumNumberOfWorkers??this.minimumNumberOfWorkers),...e}}setTasksQueueSize(e){for(const t of this.workerNodes)t.tasksQueueBackPressureSize=e}setTaskStealing(){for(const e of this.workerNodes.keys())this.workerNodes[e].on("idle",this.handleWorkerNodeIdleEvent)}unsetTaskStealing(){for(const e of this.workerNodes.keys())this.workerNodes[e].off("idle",this.handleWorkerNodeIdleEvent)}setTasksStealingOnBackPressure(){for(const e of this.workerNodes.keys())this.workerNodes[e].on("backPressure",this.handleWorkerNodeBackPressureEvent)}unsetTasksStealingOnBackPressure(){for(const e of this.workerNodes.keys())this.workerNodes[e].off("backPressure",this.handleWorkerNodeBackPressureEvent)}get full(){return this.workerNodes.length>=(this.maximumNumberOfWorkers??this.minimumNumberOfWorkers)}internalBusy(){return!0===this.opts.enableTasksQueue?-1===this.workerNodes.findIndex((e=>e.info.ready&&e.usage.tasks.executing<this.opts.tasksQueueOptions.concurrency)):-1===this.workerNodes.findIndex((e=>e.info.ready&&0===e.usage.tasks.executing))}isWorkerNodeBusy(e){return!0===this.opts.enableTasksQueue?this.workerNodes[e].usage.tasks.executing>=this.opts.tasksQueueOptions.concurrency:this.workerNodes[e].usage.tasks.executing>0}async sendTaskFunctionOperationToWorker(e,t){return await new Promise(((r,s)=>{const i=t=>{this.checkMessageWorkerId(t);const o=this.getWorkerInfo(e)?.id;null!=t.taskFunctionOperationStatus&&t.workerId===o&&(t.taskFunctionOperationStatus?r(!0):s(new Error(`Task function operation '${t.taskFunctionOperation}' failed on worker ${t.workerId} with error: '${t.workerError?.message}'`)),this.deregisterWorkerMessageListener(this.getWorkerNodeKeyByWorkerId(t.workerId),i))};this.registerWorkerMessageListener(e,i),this.sendToWorker(e,t)}))}async sendTaskFunctionOperationToWorkers(e){return await new Promise(((t,r)=>{const s=new Array,i=e=>{if(this.checkMessageWorkerId(e),null!=e.taskFunctionOperationStatus&&(s.push(e),s.length===this.workerNodes.length)){if(s.every((e=>!0===e.taskFunctionOperationStatus)))t(!0);else if(s.some((e=>!1===e.taskFunctionOperationStatus))){const t=s.find((e=>!1===e.taskFunctionOperationStatus));r(new Error(`Task function operation '${e.taskFunctionOperation}' failed on worker ${t?.workerId} with error: '${t?.workerError?.message}'`))}this.deregisterWorkerMessageListener(this.getWorkerNodeKeyByWorkerId(e.workerId),i)}};for(const t of this.workerNodes.keys())this.registerWorkerMessageListener(t,i),this.sendToWorker(t,e)}))}hasTaskFunction(e){return this.listTaskFunctionsProperties().some((t=>t.name===e))}async addTaskFunction(e,t){if("string"!=typeof e)throw new TypeError("name argument must be a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("name argument must not be an empty string");if("function"==typeof t&&(t={taskFunction:t}),"function"!=typeof t.taskFunction)throw new TypeError("taskFunction property must be a function");U(t.priority),B(t.strategy);const r=await this.sendTaskFunctionOperationToWorkers({taskFunctionOperation:"add",taskFunctionProperties:P(e,t),taskFunction:t.taskFunction.toString()});this.taskFunctions.set(e,t),this.workerChoiceStrategiesContext?.syncWorkerChoiceStrategies(this.getWorkerWorkerChoiceStrategies());for(const e of this.workerNodes.keys())this.sendStatisticsMessageToWorker(e);return r}async removeTaskFunction(e){if(!this.taskFunctions.has(e))throw new Error("Cannot remove a task function not handled on the pool side");const t=await this.sendTaskFunctionOperationToWorkers({taskFunctionOperation:"remove",taskFunctionProperties:P(e,this.taskFunctions.get(e))});for(const t of this.workerNodes)t.deleteTaskFunctionWorkerUsage(e);this.taskFunctions.delete(e),this.workerChoiceStrategiesContext?.syncWorkerChoiceStrategies(this.getWorkerWorkerChoiceStrategies());for(const e of this.workerNodes.keys())this.sendStatisticsMessageToWorker(e);return t}listTaskFunctionsProperties(){for(const e of this.workerNodes)if(Array.isArray(e.info.taskFunctionsProperties)&&e.info.taskFunctionsProperties.length>0)return e.info.taskFunctionsProperties;return[]}getTaskFunctionWorkerWorkerChoiceStrategy=e=>{if(null!=e)return this.listTaskFunctionsProperties().find((t=>t.name===e))?.strategy};getWorkerNodeTaskFunctionPriority=(e,t)=>{if(null!=t)return this.getWorkerInfo(e)?.taskFunctionsProperties?.find((e=>e.name===t))?.priority};getWorkerWorkerChoiceStrategies=()=>new Set([this.opts.workerChoiceStrategy,...this.listTaskFunctionsProperties().map((e=>e.strategy)).filter((e=>null!=e))]);async setDefaultTaskFunction(e){return await this.sendTaskFunctionOperationToWorkers({taskFunctionOperation:"default",taskFunctionProperties:P(e,this.taskFunctions.get(e))})}shallExecuteTask(e){return 0===this.tasksQueueSize(e)&&this.workerNodes[e].usage.tasks.executing<this.opts.tasksQueueOptions.concurrency}async execute(e,t,r){return await new Promise(((s,i)=>{if(!this.started)return void i(new Error("Cannot execute a task on not started pool"));if(this.destroying)return void i(new Error("Cannot execute a task on destroying pool"));if(null!=t&&"string"!=typeof t)return void i(new TypeError("name argument must be a string"));if(null!=t&&"string"==typeof t&&0===t.trim().length)return void i(new TypeError("name argument must not be an empty string"));if(null!=r&&!Array.isArray(r))return void i(new TypeError("transferList argument must be an array"));const o=w.now(),n=this.getTaskFunctionWorkerWorkerChoiceStrategy(t),a=this.chooseWorkerNode(n),u={name:t??T,data:e??{},priority:this.getWorkerNodeTaskFunctionPriority(a,t),strategy:n,transferList:r,timestamp:o,taskId:c()};this.promiseResponseMap.set(u.taskId,{resolve:s,reject:i,workerNodeKey:a,...null!=this.emitter&&{asyncResource:new g("poolifier:task",{triggerAsyncId:this.emitter.asyncId,requireManualDestroy:!0})}}),!1===this.opts.enableTasksQueue||!0===this.opts.enableTasksQueue&&this.shallExecuteTask(a)?this.executeTask(a,u):this.enqueueTask(a,u)}))}startMinimumNumberOfWorkers(e=!1){for(this.startingMinimumNumberOfWorkers=!0;this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.minimumNumberOfWorkers;){const t=this.createAndSetupWorkerNode();e&&this.initWorkerNodeUsage(this.workerNodes[t])}this.startingMinimumNumberOfWorkers=!1}start(){if(this.started)throw new Error("Cannot start an already started pool");if(this.starting)throw new Error("Cannot start an already starting pool");if(this.destroying)throw new Error("Cannot start a destroying pool");this.starting=!0,this.startMinimumNumberOfWorkers(),this.startTimestamp=w.now(),this.starting=!1,this.started=!0}async destroy(){if(!this.started)throw new Error("Cannot destroy an already destroyed pool");if(this.starting)throw new Error("Cannot destroy an starting pool");if(this.destroying)throw new Error("Cannot destroy an already destroying pool");this.destroying=!0,await Promise.all(this.workerNodes.map((async(e,t)=>{await this.destroyWorkerNode(t)}))),this.emitter?.emit(f.destroy,this.info),this.emitter?.emitDestroy(),this.readyEventEmitted=!1,delete this.startTimestamp,this.destroying=!1,this.started=!1}async sendKillMessageToWorker(e){await new Promise(((t,r)=>{if(null==this.workerNodes[e])return void t();this.registerWorkerMessageListener(e,(e=>{this.checkMessageWorkerId(e),"success"===e.kill?t():"failure"===e.kill&&r(new Error(`Kill message handling failed on worker ${e.workerId}`))})),this.sendToWorker(e,{kill:!0})}))}async destroyWorkerNode(e){this.flagWorkerNodeAsNotReady(e);const t=this.flushTasksQueue(e),r=this.workerNodes[e];await(async(e,t,r,s)=>await new Promise((i=>{let o=0;0!==r?(e.on(t,(()=>{++o,o===r&&i(o)})),s>=0&&setTimeout((()=>{i(o)}),s)):i(o)})))(r,"taskFinished",t,this.opts.tasksQueueOptions?.tasksFinishedTimeout??K(this.maximumNumberOfWorkers??this.minimumNumberOfWorkers).tasksFinishedTimeout),await this.sendKillMessageToWorker(e),await r.terminate()}setupHook(){}beforeTaskExecutionHook(e,t){if(null!=this.workerNodes[e]?.usage){const r=this.workerNodes[e].usage;++r.tasks.executing,H(this.workerChoiceStrategiesContext,r,t)}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name)){const r=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name);++r.tasks.executing,H(this.workerChoiceStrategiesContext,r,t)}}afterTaskExecutionHook(e,t){let r=!1;if(null!=this.workerNodes[e]?.usage){const s=this.workerNodes[e].usage;_(s,t),$(this.workerChoiceStrategiesContext,s,t),j(this.workerChoiceStrategiesContext,s,t),r=!0}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance.name)){const s=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance.name);_(s,t),$(this.workerChoiceStrategiesContext,s,t),j(this.workerChoiceStrategiesContext,s,t),r=!0}r&&this.workerChoiceStrategiesContext?.update(e)}shallUpdateTaskFunctionWorkerUsage(e){const t=this.getWorkerInfo(e);return null!=t&&Array.isArray(t.taskFunctionsProperties)&&t.taskFunctionsProperties.length>2}chooseWorkerNode(e){if(this.shallCreateDynamicWorker()){const e=this.createAndSetupDynamicWorkerNode();if(!0===this.workerChoiceStrategiesContext?.getPolicy().dynamicWorkerUsage)return e}return this.workerChoiceStrategiesContext.execute(e)}initWorkerNodeUsage(e){!0===this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements().runTime.aggregate&&(e.usage.runTime.aggregate=O(...this.workerNodes.map((e=>e.usage.runTime.aggregate??1/0)))),!0===this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements().waitTime.aggregate&&(e.usage.waitTime.aggregate=O(...this.workerNodes.map((e=>e.usage.waitTime.aggregate??1/0)))),!0===this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements().elu.aggregate&&(e.usage.elu.active.aggregate=O(...this.workerNodes.map((e=>e.usage.elu.active.aggregate??1/0))))}createAndSetupWorkerNode(){const e=this.createWorkerNode();e.registerWorkerEventHandler("online",this.opts.onlineHandler??W),e.registerWorkerEventHandler("message",this.opts.messageHandler??W),e.registerWorkerEventHandler("error",this.opts.errorHandler??W),e.registerOnceWorkerEventHandler("error",(t=>{e.info.ready=!1,this.emitter?.emit(f.error,t),this.started&&!this.destroying&&!0===this.opts.restartWorkerOnError&&(e.info.dynamic?this.createAndSetupDynamicWorkerNode():this.startingMinimumNumberOfWorkers||this.startMinimumNumberOfWorkers(!0)),this.started&&!this.destroying&&!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(this.workerNodes.indexOf(e)),e?.terminate().catch((e=>{this.emitter?.emit(f.error,e)}))})),e.registerWorkerEventHandler("exit",this.opts.exitHandler??W),e.registerOnceWorkerEventHandler("exit",(()=>{this.removeWorkerNode(e),!this.started||this.startingMinimumNumberOfWorkers||this.destroying||this.startMinimumNumberOfWorkers(!0)}));const t=this.addWorkerNode(e);return this.afterWorkerNodeSetup(t),t}createAndSetupDynamicWorkerNode(){const e=this.createAndSetupWorkerNode();if(this.registerWorkerMessageListener(e,(e=>{this.checkMessageWorkerId(e);const t=this.getWorkerNodeKeyByWorkerId(e.workerId),r=this.workerNodes[t]?.usage;(C(Y.HARD,e.kill)||C(Y.SOFT,e.kill)&&(!1===this.opts.enableTasksQueue&&0===r.tasks.executing||!0===this.opts.enableTasksQueue&&0===r.tasks.executing&&0===this.tasksQueueSize(t)))&&(this.flagWorkerNodeAsNotReady(t),this.destroyWorkerNode(t).catch((e=>{this.emitter?.emit(f.error,e)})))})),this.sendToWorker(e,{checkActive:!0}),this.taskFunctions.size>0)for(const[t,r]of this.taskFunctions)this.sendTaskFunctionOperationToWorker(e,{taskFunctionOperation:"add",taskFunctionProperties:P(t,r),taskFunction:r.taskFunction.toString()}).catch((e=>{this.emitter?.emit(f.error,e)}));const t=this.workerNodes[e];return t.info.dynamic=!0,!0!==this.workerChoiceStrategiesContext?.getPolicy().dynamicWorkerReady&&!0!==this.workerChoiceStrategiesContext?.getPolicy().dynamicWorkerUsage||(t.info.ready=!0),this.initWorkerNodeUsage(t),this.checkAndEmitDynamicWorkerCreationEvents(),e}afterWorkerNodeSetup(e){this.registerWorkerMessageListener(e,this.workerMessageListener),this.sendStartupMessageToWorker(e),this.sendStatisticsMessageToWorker(e),!0===this.opts.enableTasksQueue&&(!0===this.opts.tasksQueueOptions?.taskStealing&&this.workerNodes[e].on("idle",this.handleWorkerNodeIdleEvent),!0===this.opts.tasksQueueOptions?.tasksStealingOnBackPressure&&this.workerNodes[e].on("backPressure",this.handleWorkerNodeBackPressureEvent))}sendStatisticsMessageToWorker(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements().runTime.aggregate??!1,elu:this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements().elu.aggregate??!1}})}cannotStealTask(){return this.workerNodes.length<=1||0===this.info.queuedTasks}handleTask(e,t){this.shallExecuteTask(e)?this.executeTask(e,t):this.enqueueTask(e,t)}redistributeQueuedTasks(e){if(-1!==e&&!this.cannotStealTask())for(;this.tasksQueueSize(e)>0;){const t=this.workerNodes.reduce(((e,t,r,s)=>t.info.ready&&t.usage.tasks.queued<s[e].usage.tasks.queued?r:e),0);this.handleTask(t,this.dequeueTask(e))}}updateTaskStolenStatisticsWorkerUsage(e,t){const r=this.workerNodes[e];if(null!=r?.usage&&++r.usage.tasks.stolen,this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=r.getTaskFunctionWorkerUsage(t)){++r.getTaskFunctionWorkerUsage(t).tasks.stolen}}updateTaskSequentiallyStolenStatisticsWorkerUsage(e){const t=this.workerNodes[e];null!=t?.usage&&++t.usage.tasks.sequentiallyStolen}updateTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(e,t){const r=this.workerNodes[e];if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=r.getTaskFunctionWorkerUsage(t)){++r.getTaskFunctionWorkerUsage(t).tasks.sequentiallyStolen}}resetTaskSequentiallyStolenStatisticsWorkerUsage(e){const t=this.workerNodes[e];null!=t?.usage&&(t.usage.tasks.sequentiallyStolen=0)}resetTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(e,t){const r=this.workerNodes[e];if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=r.getTaskFunctionWorkerUsage(t)){r.getTaskFunctionWorkerUsage(t).tasks.sequentiallyStolen=0}}handleWorkerNodeIdleEvent=(e,t)=>{const{workerNodeKey:r}=e;if(null==r)throw new Error("WorkerNode event detail 'workerNodeKey' property must be defined");const s=this.getWorkerInfo(r);if(this.cannotStealTask()||(this.info.stealingWorkerNodes??0)>Math.floor(this.workerNodes.length/2))return void(null!=s&&null!=t&&(s.stealing=!1));const i=this.workerNodes[r].usage.tasks;if(null!=s&&null!=t&&i.sequentiallyStolen>0&&(i.executing>0||this.tasksQueueSize(r)>0)){s.stealing=!1;for(const e of s.taskFunctionsProperties)this.resetTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(r,e.name);return void this.resetTaskSequentiallyStolenStatisticsWorkerUsage(r)}if(null==s)throw new Error(`Worker node with key '${r}' not found in pool`);s.stealing=!0;const o=this.workerNodeStealTask(r);if(this.shallUpdateTaskFunctionWorkerUsage(r)&&null!=o){const e=this.workerNodes[r].getTaskFunctionWorkerUsage(o.name).tasks;0===e.sequentiallyStolen||null!=t&&t.name===o.name&&e.sequentiallyStolen>0?this.updateTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(r,o.name):this.resetTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(r,o.name)}(async e=>{await new Promise((t=>{setTimeout(t,e)}))})(((e=0,t=100)=>{const r=Math.pow(2,e)*t;return r+.2*r*F()})(i.sequentiallyStolen)).then((()=>{this.handleWorkerNodeIdleEvent(e,o)})).catch((e=>{this.emitter?.emit(f.error,e)}))};workerNodeStealTask=e=>{const t=this.workerNodes.slice().sort(((e,t)=>t.usage.tasks.queued-e.usage.tasks.queued)).find(((t,r)=>t.info.ready&&!t.info.stealing&&r!==e&&t.usage.tasks.queued>0));if(null!=t){const r=t.dequeueLastBucketTask();return this.handleTask(e,r),this.updateTaskSequentiallyStolenStatisticsWorkerUsage(e),this.updateTaskStolenStatisticsWorkerUsage(e,r.name),r}};handleWorkerNodeBackPressureEvent=e=>{if(this.cannotStealTask()||(this.info.stealingWorkerNodes??0)>Math.floor(this.workerNodes.length/2))return;const{workerId:t}=e;if(this.opts.tasksQueueOptions.size<=1)return;const r=this.workerNodes[this.getWorkerNodeKeyByWorkerId(t)],s=this.workerNodes.slice().sort(((e,t)=>e.usage.tasks.queued-t.usage.tasks.queued));for(const[e,i]of s.entries())if(r.usage.tasks.queued>0&&i.info.ready&&!i.info.stealing&&i.info.id!==t&&i.usage.tasks.queued<this.opts.tasksQueueOptions.size-1){const t=this.getWorkerInfo(e);if(null==t)throw new Error(`Worker node with key '${e}' not found in pool`);t.stealing=!0;const s=r.dequeueLastBucketTask();this.handleTask(e,s),this.updateTaskStolenStatisticsWorkerUsage(e,s.name),t.stealing=!1}};workerMessageListener=e=>{this.checkMessageWorkerId(e);const{workerId:t,ready:r,taskId:s,taskFunctionsProperties:i}=e;if(null!=r&&null!=i)this.handleWorkerReadyResponse(e);else if(null!=i){const e=this.getWorkerNodeKeyByWorkerId(t),r=this.getWorkerInfo(e);null!=r&&(r.taskFunctionsProperties=i,this.sendStatisticsMessageToWorker(e))}else null!=s&&this.handleTaskExecutionResponse(e)};checkAndEmitReadyEvent(){!this.readyEventEmitted&&this.ready&&(this.emitter?.emit(f.ready,this.info),this.readyEventEmitted=!0)}handleWorkerReadyResponse(e){const{workerId:t,ready:r,taskFunctionsProperties:s}=e;if(null==r||!r)throw new Error(`Worker ${t} failed to initialize`);const i=this.getWorkerNodeKeyByWorkerId(t),o=this.workerNodes[i];o.info.ready=r,o.info.taskFunctionsProperties=s,this.sendStatisticsMessageToWorker(i),this.checkAndEmitReadyEvent()}handleTaskExecutionResponse(e){const{workerId:t,taskId:r,workerError:s,data:i}=e,o=this.promiseResponseMap.get(r);if(null!=o){const{resolve:n,reject:a,workerNodeKey:u,asyncResource:h}=o,k=this.workerNodes[u];if(null!=s?(this.emitter?.emit(f.taskError,s),null!=h?h.runInAsyncScope(a,this.emitter,s.message):a(s.message)):null!=h?h.runInAsyncScope(n,this.emitter,i):n(i),h?.emitDestroy(),this.afterTaskExecutionHook(u,e),this.promiseResponseMap.delete(r),k?.emit("taskFinished",r),!0===this.opts.enableTasksQueue&&!this.destroying&&null!=k){const e=k.usage.tasks;this.tasksQueueSize(u)>0&&e.executing<this.opts.tasksQueueOptions.concurrency&&this.executeTask(u,this.dequeueTask(u)),0===e.executing&&0===this.tasksQueueSize(u)&&0===e.sequentiallyStolen&&k.emit("idle",{workerId:t,workerNodeKey:u})}}}checkAndEmitTaskExecutionEvents(){this.busy&&this.emitter?.emit(f.busy,this.info)}checkAndEmitTaskQueuingEvents(){this.hasBackPressure()&&this.emitter?.emit(f.backPressure,this.info)}getWorkerInfo(e){return this.workerNodes[e]?.info}createWorkerNode(){const e=new ge(this.worker,this.filePath,{env:this.opts.env,workerOptions:this.opts.workerOptions,tasksQueueBackPressureSize:this.opts.tasksQueueOptions?.size??K(this.maximumNumberOfWorkers??this.minimumNumberOfWorkers).size,tasksQueueBucketSize:2*(this.maximumNumberOfWorkers??this.minimumNumberOfWorkers)});return this.starting&&(e.info.ready=!0),e}addWorkerNode(e){this.workerNodes.push(e);const t=this.workerNodes.indexOf(e);if(-1===t)throw new Error("Worker added not found in worker nodes");return t}checkAndEmitEmptyEvent(){this.empty&&(this.emitter?.emit(f.empty,this.info),this.readyEventEmitted=!1)}removeWorkerNode(e){const t=this.workerNodes.indexOf(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategiesContext?.remove(t)),this.checkAndEmitEmptyEvent()}flagWorkerNodeAsNotReady(e){const t=this.getWorkerInfo(e);null!=t&&(t.ready=!1)}hasBackPressure(){return!0===this.opts.enableTasksQueue&&-1===this.workerNodes.findIndex((e=>!e.hasBackPressure()))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(e,t,t.transferList),this.checkAndEmitTaskExecutionEvents()}enqueueTask(e,t){const r=this.workerNodes[e].enqueueTask(t);return this.checkAndEmitTaskQueuingEvents(),r}dequeueTask(e){return this.workerNodes[e].dequeueTask()}tasksQueueSize(e){return this.workerNodes[e].tasksQueueSize()}flushTasksQueue(e){let t=0;for(;this.tasksQueueSize(e)>0;)this.executeTask(e,this.dequeueTask(e)),++t;return this.workerNodes[e].clearTasksQueue(),t}flushTasksQueues(){for(const e of this.workerNodes.keys())this.flushTasksQueue(e)}}class pe extends me{constructor(e,t,r={},s){super(e,t,r,s)}setupHook(){e.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return e.isPrimary}sendToWorker(e,t){this.workerNodes[e]?.worker.send({...t,workerId:this.getWorkerInfo(e)?.id})}sendStartupMessageToWorker(e){this.sendToWorker(e,{ready:!1})}registerWorkerMessageListener(e,t){this.workerNodes[e].worker.on("message",t)}registerOnceWorkerMessageListener(e,t){this.workerNodes[e].worker.once("message",t)}deregisterWorkerMessageListener(e,t){this.workerNodes[e].worker.off("message",t)}shallCreateDynamicWorker(){return!1}checkAndEmitDynamicWorkerCreationEvents(){}get type(){return y.fixed}get worker(){return M.cluster}get busy(){return this.internalBusy()}}class we extends pe{constructor(e,t,r,s={}){super(e,r,s,t),Q(this.minimumNumberOfWorkers,this.maximumNumberOfWorkers)}shallCreateDynamicWorker(){return!this.full&&this.internalBusy()||this.empty}checkAndEmitDynamicWorkerCreationEvents(){this.full&&this.emitter?.emit(f.full,this.info)}get type(){return y.dynamic}get busy(){return this.full&&this.internalBusy()}}class ye extends me{constructor(e,t,r={},s){super(e,t,r,s)}isMain(){return a}sendToWorker(e,t,r){this.workerNodes[e]?.messageChannel?.port1.postMessage({...t,workerId:this.getWorkerInfo(e)?.id},r)}sendStartupMessageToWorker(e){const t=this.workerNodes[e],r=t.messageChannel.port2;t.worker.postMessage({ready:!1,workerId:this.getWorkerInfo(e)?.id,port:r},[r])}registerWorkerMessageListener(e,t){this.workerNodes[e].messageChannel?.port1.on("message",t)}registerOnceWorkerMessageListener(e,t){this.workerNodes[e].messageChannel?.port1.once("message",t)}deregisterWorkerMessageListener(e,t){this.workerNodes[e].messageChannel?.port1.off("message",t)}shallCreateDynamicWorker(){return!1}checkAndEmitDynamicWorkerCreationEvents(){}get type(){return y.fixed}get worker(){return M.thread}get busy(){return this.internalBusy()}}class fe extends ye{constructor(e,t,r,s={}){super(e,r,s,t),Q(this.minimumNumberOfWorkers,this.maximumNumberOfWorkers)}shallCreateDynamicWorker(){return!this.full&&this.internalBusy()||this.empty}checkAndEmitDynamicWorkerCreationEvents(){this.full&&this.emitter?.emit(f.full,this.info)}get type(){return y.dynamic}get busy(){return this.full&&this.internalBusy()}}const Te=(e,t)=>{if("string"!=typeof e)throw new TypeError("A taskFunctions parameter object key is not a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("A taskFunctions parameter object key is an empty string");if("function"!=typeof t.taskFunction)throw new TypeError(`taskFunction object 'taskFunction' property '${t.taskFunction}' is not a function`);U(t.priority),B(t.strategy)},We=e=>{if("string"!=typeof e)throw new TypeError("name parameter is not a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("name parameter is an empty string")},Ne=6e4,Se={killBehavior:Y.SOFT,maxInactiveTime:Ne,killHandler:W};class Ee{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,r,s=Se){if(this.isMain=e,this.mainWorker=t,this.opts=s,null==this.isMain)throw new Error("isMain parameter is mandatory");this.checkTaskFunctions(r),this.checkWorkerOptions(this.opts),this.isMain||this.getMainWorker().on("message",this.handleReadyMessage.bind(this))}checkWorkerOptions(e){(e=>{if(null!=e&&!x(e))throw new TypeError("opts worker options parameter is not a plain object");if(null!=e?.killBehavior&&!Object.values(Y).includes(e.killBehavior))throw new TypeError(`killBehavior option '${e.killBehavior}' is not valid`);if(null!=e?.maxInactiveTime&&!Number.isSafeInteger(e.maxInactiveTime))throw new TypeError("maxInactiveTime option is not an integer");if(null!=e?.maxInactiveTime&&e.maxInactiveTime<5)throw new TypeError("maxInactiveTime option is not a positive integer greater or equal than 5");if(null!=e?.killHandler&&"function"!=typeof e.killHandler)throw new TypeError("killHandler option is not a function")})(e),this.opts={...Se,...e}}checkTaskFunctions(e){if(null==e)throw new Error("taskFunctions parameter is mandatory");if(this.taskFunctions=new Map,"function"==typeof e){const t={taskFunction:e.bind(this)};this.taskFunctions.set(T,t),this.taskFunctions.set("string"==typeof e.name&&e.name.trim().length>0?e.name:"fn1",t)}else{if(!x(e))throw new TypeError("taskFunctions parameter is not a function or a plain object");{let t=!0;for(let[r,s]of Object.entries(e))"function"==typeof s&&(s={taskFunction:s}),Te(r,s),s.taskFunction=s.taskFunction.bind(this),t&&(this.taskFunctions.set(T,s),t=!1),this.taskFunctions.set(r,s);if(t)throw new Error("taskFunctions parameter object is empty")}}}hasTaskFunction(e){try{We(e)}catch(e){return{status:!1,error:e}}return{status:this.taskFunctions.has(e)}}addTaskFunction(e,t){try{if(We(e),e===T)throw new Error("Cannot add a task function with the default reserved name");return"function"==typeof t&&(t={taskFunction:t}),Te(e,t),t.taskFunction=t.taskFunction.bind(this),this.taskFunctions.get(e)===this.taskFunctions.get(T)&&this.taskFunctions.set(T,t),this.taskFunctions.set(e,t),this.sendTaskFunctionsPropertiesToMainWorker(),{status:!0}}catch(e){return{status:!1,error:e}}}removeTaskFunction(e){try{if(We(e),e===T)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(T))throw new Error("Cannot remove the task function used as the default task function");const t=this.taskFunctions.delete(e);return this.sendTaskFunctionsPropertiesToMainWorker(),{status:t}}catch(e){return{status:!1,error:e}}}listTaskFunctionsProperties(){let e=T;for(const[t,r]of this.taskFunctions)if(t!==T&&r===this.taskFunctions.get(T)){e=t;break}const t=[];for(const[r,s]of this.taskFunctions)r!==T&&r!==e&&t.push(P(r,s));return[P(T,this.taskFunctions.get(T)),P(e,this.taskFunctions.get(e)),...t]}setDefaultTaskFunction(e){try{if(We(e),e===T)throw new Error("Cannot set the default task function reserved name as the default task function");if(!this.taskFunctions.has(e))throw new Error("Cannot set the default task function to a non-existing task function");return this.taskFunctions.set(T,this.taskFunctions.get(e)),this.sendTaskFunctionsPropertiesToMainWorker(),{status:!0}}catch(e){return{status:!1,error:e}}}messageListener(e){this.checkMessageWorkerId(e);const{statistics:t,checkActive:r,taskFunctionOperation:s,taskId:i,data:o,kill:n}=e;null!=t?this.statistics=t:null!=r?r?this.startCheckActive():this.stopCheckActive():null!=s?this.handleTaskFunctionOperationMessage(e):null!=i&&null!=o?this.run(e):!0===n&&this.handleKillMessage(e)}handleTaskFunctionOperationMessage(e){const{taskFunctionOperation:t,taskFunctionProperties:r,taskFunction:s}=e;if(null==r)throw new Error("Cannot handle task function operation message without task function properties");let i;switch(t){case"add":i=this.addTaskFunction(r.name,{taskFunction:new Function(`return ${s}`)(),...null!=r.priority&&{priority:r.priority},...null!=r.strategy&&{strategy:r.strategy}});break;case"remove":i=this.removeTaskFunction(r.name);break;case"default":i=this.setDefaultTaskFunction(r.name);break;default:i={status:!1,error:new Error("Unknown task operation")}}this.sendToMainWorker({taskFunctionOperation:t,taskFunctionOperationStatus:i.status,taskFunctionProperties:r,...!i.status&&null!=i.error&&{workerError:{name:r.name,message:this.handleError(i.error)}}})}handleKillMessage(e){if(this.stopCheckActive(),b(this.opts.killHandler))this.opts.killHandler().then((()=>{this.sendToMainWorker({kill:"success"})})).catch((()=>{this.sendToMainWorker({kill:"failure"})}));else try{this.opts.killHandler?.(),this.sendToMainWorker({kill:"success"})}catch{this.sendToMainWorker({kill:"failure"})}}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Message worker id is not set");if(e.workerId!==this.id)throw new Error(`Message worker id ${e.workerId} does not match the worker id ${this.id}`)}startCheckActive(){this.lastTaskTimestamp=w.now(),this.activeInterval=setInterval(this.checkActive.bind(this),(this.opts.maxInactiveTime??Ne)/2)}stopCheckActive(){null!=this.activeInterval&&(clearInterval(this.activeInterval),delete this.activeInterval)}checkActive(){w.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??Ne)&&this.sendToMainWorker({kill:this.opts.killBehavior})}getMainWorker(){if(null==this.mainWorker)throw new Error("Main worker not set");return this.mainWorker}sendTaskFunctionsPropertiesToMainWorker(){this.sendToMainWorker({taskFunctionsProperties:this.listTaskFunctionsProperties()})}handleError(e){return e instanceof Error?e.message:e}run=e=>{const{name:t,taskId:r,data:s}=e,i=t??T;if(!this.taskFunctions.has(i))return void this.sendToMainWorker({workerError:{name:t,message:`Task function '${t}' not found`,data:s},taskId:r});const o=this.taskFunctions.get(i)?.taskFunction;b(o)?this.runAsync(o,e):this.runSync(o,e)};runSync=(e,t)=>{const{name:r,taskId:s,data:i}=t;try{let t=this.beginTaskPerformance(r);const o=e(i);t=this.endTaskPerformance(t),this.sendToMainWorker({data:o,taskPerformance:t,taskId:s})}catch(e){this.sendToMainWorker({workerError:{name:r,message:this.handleError(e),data:i},taskId:s})}finally{this.updateLastTaskTimestamp()}};runAsync=(e,t)=>{const{name:r,taskId:s,data:i}=t;let o=this.beginTaskPerformance(r);e(i).then((e=>{o=this.endTaskPerformance(o),this.sendToMainWorker({data:e,taskPerformance:o,taskId:s})})).catch((e=>{this.sendToMainWorker({workerError:{name:r,message:this.handleError(e),data:i},taskId:s})})).finally((()=>{this.updateLastTaskTimestamp()})).catch(W)};beginTaskPerformance(e){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set");return{name:e??T,timestamp:w.now(),...this.statistics.elu&&{elu:w.eventLoopUtilization()}}}endTaskPerformance(e){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set");return{...e,...this.statistics.runTime&&{runTime:w.now()-e.timestamp},...this.statistics.elu&&{elu:w.eventLoopUtilization(e.elu)}}}updateLastTaskTimestamp(){null!=this.activeInterval&&(this.lastTaskTimestamp=w.now())}}class ve extends Ee{constructor(t,r={}){super(e.isPrimary,e.worker,t,r)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready)try{this.getMainWorker().on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctionsProperties:this.listTaskFunctionsProperties()})}catch{this.sendToMainWorker({ready:!1,taskFunctionsProperties:this.listTaskFunctionsProperties()})}}get id(){return this.getMainWorker().id}sendToMainWorker=e=>{this.getMainWorker().send({...e,workerId:this.id})}}class xe extends Ee{port;constructor(e,t={}){super(a,u,e,t)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready&&null!=e.port)try{this.port=e.port,this.port.on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctionsProperties:this.listTaskFunctionsProperties()})}catch{this.sendToMainWorker({ready:!1,taskFunctionsProperties:this.listTaskFunctionsProperties()})}}handleKillMessage(e){super.handleKillMessage(e),this.port?.unref(),this.port?.close()}get id(){return h}sendToMainWorker=e=>{this.port?.postMessage({...e,workerId:this.id})};handleError(e){return e}}export{ve as ClusterWorker,we as DynamicClusterPool,fe as DynamicThreadPool,pe as FixedClusterPool,ye as FixedThreadPool,Y as KillBehaviors,z as Measurements,f as PoolEvents,y as PoolTypes,xe as ThreadWorker,R as WorkerChoiceStrategies,M as WorkerTypes,N as availableParallelism};
|
|
1
|
+
import e,{Worker as t}from"node:cluster";import{existsSync as s}from"node:fs";import{env as r}from"node:process";import{Worker as i,SHARE_ENV as o,MessageChannel as n,isMainThread as a,parentPort as u,threadId as h}from"node:worker_threads";import{getRandomValues as k,randomUUID as c}from"node:crypto";import*as d from"node:os";import{cpus as l}from"node:os";import{AsyncResource as g}from"node:async_hooks";import{EventEmitter as m,EventEmitterAsyncResource as p}from"node:events";import{performance as w}from"node:perf_hooks";const y=Object.freeze({fixed:"fixed",dynamic:"dynamic"}),f=Object.freeze({ready:"ready",busy:"busy",full:"full",empty:"empty",destroy:"destroy",error:"error",taskError:"taskError",backPressure:"backPressure"}),T="default",W=Object.freeze((()=>{})),N=()=>{let e=1;try{e=d.availableParallelism()}catch{const t=d.cpus();Array.isArray(t)&&t.length>0&&(e=t.length)}return e},S=e=>Array.isArray(e)&&0===e.length?0:Array.isArray(e)&&1===e.length?e[0]:e.reduce(((e,t)=>e+t),0)/e.length,E=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},v=(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),C=(e,t)=>t===e,b=e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name,F=()=>k(new Uint32Array(1))[0]/4294967296,O=(...e)=>e.reduce(((e,t)=>e<t?e:t),1/0),I=(...e)=>e.reduce(((e,t)=>e>t?e:t),-1/0),P=(e,t)=>({name:e,...null!=t?.priority&&{priority:t.priority},...null!=t?.strategy&&{strategy:t.strategy}}),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"}),z=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"}),M=Object.freeze({thread:"thread",cluster:"cluster"}),q={aggregate:!1,average:!1,median:!1},K=e=>({size:Math.pow(e,2),concurrency:1,taskStealing:!0,tasksStealingOnBackPressure:!1,tasksFinishedTimeout:2e3}),A=e=>{if(null==e)throw new TypeError("The worker file path must be specified");if("string"!=typeof e)throw new TypeError("The worker file path must be a string");if(!s(e))throw new Error(`Cannot find the worker file '${e}'`)},Q=(e,t)=>{if(null==t)throw new TypeError("Cannot instantiate a dynamic pool without specifying the maximum pool size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot instantiate a dynamic pool with a non safe integer maximum pool size");if(e>t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size");if(0===t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size equal to zero");if(e===t)throw new RangeError("Cannot instantiate a dynamic pool with a minimum pool size equal to the maximum pool size. Use a fixed pool instead")},U=e=>{if(null!=e&&!Number.isSafeInteger(e))throw new TypeError(`Invalid property 'priority': '${e}'`);if(null!=e&&Number.isSafeInteger(e)&&(e<-20||e>19))throw new RangeError("Property 'priority' must be between -20 and 19")},B=e=>{if(null!=e&&!Object.values(R).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)},D=e=>{if(null!=e&&!x(e))throw new TypeError("Invalid tasks queue options: must be a plain object");if(null!=e?.concurrency&&!Number.isSafeInteger(e.concurrency))throw new TypeError("Invalid worker node tasks concurrency: must be an integer");if(null!=e?.concurrency&&e.concurrency<=0)throw new RangeError(`Invalid worker node tasks concurrency: ${e.concurrency} is a negative integer or zero`);if(null!=e?.size&&!Number.isSafeInteger(e.size))throw new TypeError("Invalid worker node tasks queue size: must be an integer");if(null!=e?.size&&e.size<=0)throw new RangeError(`Invalid worker node tasks queue size: ${e.size} is a negative integer or zero`)},L=(e,t,s)=>{null!=t&&null!=s&&t.aggregate&&(e.aggregate=(e.aggregate??0)+s,e.minimum=O(s,e.minimum??1/0),e.maximum=I(s,e.maximum??-1/0),(t.average||t.median)&&(e.history.push(s),t.average?e.average=S(e.history):null!=e.average&&delete e.average,t.median?e.median=E(e.history):null!=e.median&&delete e.median))};"test"===r.NODE_ENV&&(exports.updateMeasurementStatistics=L);const H=(e,t,s)=>{const r=performance.now(),i=r-(s.timestamp??r);L(t.waitTime,e?.getTaskStatisticsRequirements().waitTime,i)},_=(e,t)=>{const s=e.tasks;null!=s.executing&&s.executing>0&&--s.executing,null==t.workerError?++s.executed:++s.failed},$=(e,t,s)=>{null==s.workerError&&L(t.runTime,e?.getTaskStatisticsRequirements().runTime,s.taskPerformance?.runTime??0)},j=(e,t,s)=>{if(null!=s.workerError)return;const r=e?.getTaskStatisticsRequirements().elu;L(t.elu.active,r,s.taskPerformance?.elu?.active??0),L(t.elu.idle,r,s.taskPerformance?.elu?.idle??0),!0===r?.aggregate&&null!=s.taskPerformance?.elu&&(null!=t.elu.utilization?t.elu.utilization=(t.elu.utilization+s.taskPerformance.elu.utilization)/2:t.elu.utilization=s.taskPerformance.elu.utilization)},V=e=>e instanceof i?M.thread:e instanceof t?M.cluster:void 0,G=e=>e instanceof i?e.threadId:e instanceof t?e.id:void 0,Y=Object.freeze({SOFT:"SOFT",HARD:"HARD"});class J{pool;opts;nextWorkerNodeKey=0;previousWorkerNodeKey=0;strategyPolicy={dynamicWorkerUsage:!1,dynamicWorkerReady:!0};taskStatisticsRequirements={runTime:q,waitTime:q,elu:q};constructor(e,t){this.pool=e,this.opts=t,this.choose=this.choose.bind(this),this.setOptions(this.opts)}setTaskStatisticsRequirements(e){ue(this.taskStatisticsRequirements.runTime,e.runTime.median),ue(this.taskStatisticsRequirements.waitTime,e.waitTime.median),ue(this.taskStatisticsRequirements.elu,e.elu.median)}resetWorkerNodeKeyProperties(){this.nextWorkerNodeKey=0,this.previousWorkerNodeKey=0}setOptions(e){this.opts=ae(this.pool,e),this.setTaskStatisticsRequirements(this.opts)}isWorkerNodeReady(e){return this.pool.workerNodes[e]?.info?.ready??!1}checkNextWorkerNodeKey(){null!=this.nextWorkerNodeKey&&(this.nextWorkerNodeKey<0||!this.isWorkerNodeReady(this.nextWorkerNodeKey))&&delete this.nextWorkerNodeKey}getWorkerNodeTaskRunTime(e){return this.taskStatisticsRequirements.runTime.median?this.pool.workerNodes[e].usage.runTime.median??0:this.pool.workerNodes[e].usage.runTime.average??0}getWorkerNodeTaskWaitTime(e){return this.taskStatisticsRequirements.waitTime.median?this.pool.workerNodes[e].usage.waitTime.median??0:this.pool.workerNodes[e].usage.waitTime.average??0}getWorkerNodeTaskElu(e){return this.taskStatisticsRequirements.elu.median?this.pool.workerNodes[e].usage.elu.active.median??0:this.pool.workerNodes[e].usage.elu.active.average??0}setPreviousWorkerNodeKey(e){this.previousWorkerNodeKey=null!=e&&e>=0?e:this.previousWorkerNodeKey}}class X extends J{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:{aggregate:!0,average:!0,median:!1},elu:{aggregate:!0,average:!0,median:!1}};constructor(e,t){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){for(const e of this.pool.workerNodes)delete e.strategyData?.virtualTaskEndTimestamp;return!0}update(e){return this.pool.workerNodes[e].strategyData={virtualTaskEndTimestamp:this.computeWorkerNodeVirtualTaskEndTimestamp(e)},!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.fairShareNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}fairShareNextWorkerNodeKey(){if(0!==this.pool.workerNodes.length)return this.pool.workerNodes.reduce(((e,t,s,r)=>(null==t.strategyData?.virtualTaskEndTimestamp&&(t.strategyData={virtualTaskEndTimestamp:this.computeWorkerNodeVirtualTaskEndTimestamp(s)}),this.isWorkerNodeReady(s)&&t.strategyData.virtualTaskEndTimestamp<r[e].strategyData.virtualTaskEndTimestamp?s:e)),0)}computeWorkerNodeVirtualTaskEndTimestamp(e){return this.getWorkerNodeVirtualTaskEndTimestamp(e,this.getWorkerNodeVirtualTaskStartTimestamp(e))}getWorkerNodeVirtualTaskEndTimestamp(e,t){return t+(this.getWorkerNodeTaskWaitTime(e)+(this.opts.measurement===z.elu?this.getWorkerNodeTaskElu(e):this.getWorkerNodeTaskRunTime(e)))}getWorkerNodeVirtualTaskStartTimestamp(e){const t=this.pool.workerNodes[e]?.strategyData?.virtualTaskEndTimestamp,s=performance.now();return s<(t??-1/0)?t:s}}class Z extends J{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:{aggregate:!0,average:!0,median:!1},elu:q};roundId=0;roundWeights;workerNodeId=0;workerNodeVirtualTaskExecutionTime=0;constructor(e,t){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.roundWeights=this.getRoundWeights()}reset(){return this.resetWorkerNodeKeyProperties(),this.roundId=0,this.workerNodeId=0,this.workerNodeVirtualTaskExecutionTime=0,!0}update(){return!0}choose(){for(let e=this.roundId;e<this.roundWeights.length;e++){this.roundId=e;for(let t=this.workerNodeId;t<this.pool.workerNodes.length;t++){this.workerNodeId=t,this.workerNodeId!==this.nextWorkerNodeKey&&0!==this.workerNodeVirtualTaskExecutionTime&&(this.workerNodeVirtualTaskExecutionTime=0);const s=this.opts.weights[t];if(this.isWorkerNodeReady(t)&&s>=this.roundWeights[e]&&this.workerNodeVirtualTaskExecutionTime<s)return this.workerNodeVirtualTaskExecutionTime+=this.getWorkerNodeTaskWaitTime(t)+this.getWorkerNodeTaskRunTime(t),this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=t,this.nextWorkerNodeKey}}this.interleavedWeightedRoundRobinNextWorkerNodeId()}interleavedWeightedRoundRobinNextWorkerNodeId(){0===this.pool.workerNodes.length?this.workerNodeId=0:this.roundId===this.roundWeights.length-1&&this.workerNodeId===this.pool.workerNodes.length-1?(this.roundId=0,this.workerNodeId=0):this.workerNodeId===this.pool.workerNodes.length-1?(this.roundId=this.roundId+1,this.workerNodeId=0):this.workerNodeId=this.workerNodeId+1}remove(e){return 0===this.pool.workerNodes.length?(this.resetWorkerNodeKeyProperties(),this.workerNodeId=0,this.workerNodeVirtualTaskExecutionTime=0,!0):(this.workerNodeId===e&&this.workerNodeId>this.pool.workerNodes.length-1&&(this.workerNodeId=this.pool.workerNodes.length-1),this.previousWorkerNodeKey===e&&this.previousWorkerNodeKey>this.pool.workerNodes.length-1&&(this.previousWorkerNodeKey=this.pool.workerNodes.length-1),!0)}setOptions(e){super.setOptions(e),this.roundWeights=this.getRoundWeights()}getRoundWeights(){return[...new Set(Object.values(this.opts.weights).slice().sort(((e,t)=>e-t)))]}}class ee extends J{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:q};constructor(e,t){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastBusyNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastBusyNextWorkerNodeKey(){if(0!==this.pool.workerNodes.length)return this.pool.workerNodes.reduce(((e,t,s,r)=>this.isWorkerNodeReady(s)&&(t.usage.waitTime.aggregate??0)+(t.usage.runTime.aggregate??0)<(r[e].usage.waitTime.aggregate??0)+(r[e].usage.runTime.aggregate??0)?s:e),0)}}class te extends J{taskStatisticsRequirements={runTime:q,waitTime:q,elu:{aggregate:!0,average:!1,median:!1}};constructor(e,t){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastEluNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastEluNextWorkerNodeKey(){if(0!==this.pool.workerNodes.length)return this.pool.workerNodes.reduce(((e,t,s,r)=>this.isWorkerNodeReady(s)&&(t.usage.elu.active.aggregate??0)<(r[e].usage.elu.active.aggregate??0)?s:e),0)}}class se extends J{constructor(e,t){super(e,t)}reset(){return!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastUsedNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(){return!0}leastUsedNextWorkerNodeKey(){if(0!==this.pool.workerNodes.length)return this.pool.workerNodes.reduce(((e,t,s,r)=>this.isWorkerNodeReady(s)&&t.usage.tasks.executing+t.usage.tasks.queued<r[e].usage.tasks.executing+r[e].usage.tasks.queued?s:e),0)}}class re extends J{constructor(e,t){super(e,t)}reset(){return this.resetWorkerNodeKeyProperties(),!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;return this.setPreviousWorkerNodeKey(e),this.roundRobinNextWorkerNodeKey(),this.checkNextWorkerNodeKey(),e}remove(e){return 0===this.pool.workerNodes.length?(this.reset(),!0):(this.nextWorkerNodeKey===e&&this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1),this.previousWorkerNodeKey===e&&this.previousWorkerNodeKey>this.pool.workerNodes.length-1&&(this.previousWorkerNodeKey=this.pool.workerNodes.length-1),!0)}roundRobinNextWorkerNodeKey(){return this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,this.nextWorkerNodeKey}}class ie extends J{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:{aggregate:!0,average:!0,median:!1},elu:q};workerNodeVirtualTaskExecutionTime=0;constructor(e,t){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.resetWorkerNodeKeyProperties(),this.workerNodeVirtualTaskExecutionTime=0,!0}update(){return!0}choose(){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.weightedRoundRobinNextWorkerNodeKey(),this.checkNextWorkerNodeKey(),this.nextWorkerNodeKey}remove(e){return 0===this.pool.workerNodes.length?(this.reset(),!0):(this.nextWorkerNodeKey===e&&(this.workerNodeVirtualTaskExecutionTime=0,this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1)),this.previousWorkerNodeKey===e&&this.previousWorkerNodeKey>this.pool.workerNodes.length-1&&(this.previousWorkerNodeKey=this.pool.workerNodes.length-1),!0)}weightedRoundRobinNextWorkerNodeKey(){const e=this.opts.weights[this.nextWorkerNodeKey??this.previousWorkerNodeKey];return this.workerNodeVirtualTaskExecutionTime<e?this.workerNodeVirtualTaskExecutionTime+=this.getWorkerNodeTaskWaitTime(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+this.getWorkerNodeTaskRunTime(this.nextWorkerNodeKey??this.previousWorkerNodeKey):(this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1,this.workerNodeVirtualTaskExecutionTime=0),this.nextWorkerNodeKey}}const oe=()=>{const e=l();let t;e.every((e=>null==e.speed||0===e.speed))&&(t=(()=>{const e=performance.now(),t=performance.now()-e;return Math.trunc(15e7/t/1e3)})());let s=0;for(const r of e){null!=r.speed&&0!==r.speed||(r.speed=e.find((e=>null!=e.speed&&0!==e.speed))?.speed??t??2e3);const i=r.speed.toString().length-1;s+=1/(r.speed/Math.pow(10,i))*Math.pow(10,i)}return Math.round(s/e.length)},ne=(e,t)=>{t=t??oe();const s={};for(let r=0;r<e;r++)s[r]=t;return s},ae=(e,t)=>((t=structuredClone(t??{})).weights=t.weights??ne(e.info.maxSize),{runTime:{median:!1},waitTime:{median:!1},elu:{median:!1},...t}),ue=(e,t)=>{e.average&&t&&(e.average=!1,e.median=t),e.median&&!t&&(e.average=!0,e.median=t)},he=e=>{const t=[];for(const s of e.values())t.push(s.strategyPolicy);return{dynamicWorkerUsage:t.some((e=>e.dynamicWorkerUsage)),dynamicWorkerReady:t.some((e=>e.dynamicWorkerReady))}},ke=e=>{const t=[];for(const s of e.values())t.push(s.taskStatisticsRequirements);return{runTime:{aggregate:t.some((e=>e.runTime.aggregate)),average:t.some((e=>e.runTime.average)),median:t.some((e=>e.runTime.median))},waitTime:{aggregate:t.some((e=>e.waitTime.aggregate)),average:t.some((e=>e.waitTime.average)),median:t.some((e=>e.waitTime.median))},elu:{aggregate:t.some((e=>e.elu.aggregate)),average:t.some((e=>e.elu.average)),median:t.some((e=>e.elu.median))}}};class ce{pool;retriesCount;defaultWorkerChoiceStrategy;workerChoiceStrategies;workerChoiceStrategiesPolicy;workerChoiceStrategiesTaskStatisticsRequirements;retries;constructor(e,t=[R.ROUND_ROBIN],s){this.pool=e,this.execute=this.execute.bind(this),this.defaultWorkerChoiceStrategy=t[0],this.workerChoiceStrategies=new Map;for(const e of t)this.addWorkerChoiceStrategy(e,this.pool,s);this.workerChoiceStrategiesPolicy=he(this.workerChoiceStrategies),this.workerChoiceStrategiesTaskStatisticsRequirements=ke(this.workerChoiceStrategies),this.retriesCount=0,this.retries=((e,t)=>e.info.maxSize+Object.keys(t?.weights??ne(e.info.maxSize)).length)(this.pool,s)}getPolicy(){return this.workerChoiceStrategiesPolicy}getTaskStatisticsRequirements(){return this.workerChoiceStrategiesTaskStatisticsRequirements}setDefaultWorkerChoiceStrategy(e,t){e!==this.defaultWorkerChoiceStrategy&&(this.defaultWorkerChoiceStrategy=e,this.addWorkerChoiceStrategy(e,this.pool,t))}update(e){const t=[];for(const s of this.workerChoiceStrategies.values())t.push(s.update(e));return t.every((e=>e))}execute(e=this.defaultWorkerChoiceStrategy){return this.executeStrategy(this.workerChoiceStrategies.get(e))}executeStrategy(e){let t,s=0,r=0;do{t=e.choose(),null==t&&s>0&&(++r,++this.retriesCount),++s}while(null==t&&r<this.retries);if(null==t)throw new Error(`Worker node key chosen is null or undefined after ${r} retries`);return t}remove(e){const t=[];for(const s of this.workerChoiceStrategies.values())t.push(s.remove(e));return t.every((e=>e))}setOptions(e){for(const t of this.workerChoiceStrategies.values())t.setOptions(e)}syncWorkerChoiceStrategies(e,t){for(const t of this.workerChoiceStrategies.keys())e.has(t)||this.removeWorkerChoiceStrategy(t);for(const s of e)this.workerChoiceStrategies.has(s)||this.addWorkerChoiceStrategy(s,this.pool,t);this.workerChoiceStrategiesPolicy=he(this.workerChoiceStrategies),this.workerChoiceStrategiesTaskStatisticsRequirements=ke(this.workerChoiceStrategies)}addWorkerChoiceStrategy(e,t,s){return this.workerChoiceStrategies.has(e)?this.workerChoiceStrategies:this.workerChoiceStrategies.set(e,((e,t,s,r)=>{switch(e){case R.ROUND_ROBIN:return new(re.bind(s))(t,r);case R.LEAST_USED:return new(se.bind(s))(t,r);case R.LEAST_BUSY:return new(ee.bind(s))(t,r);case R.LEAST_ELU:return new(te.bind(s))(t,r);case R.FAIR_SHARE:return new(X.bind(s))(t,r);case R.WEIGHTED_ROUND_ROBIN:return new(ie.bind(s))(t,r);case R.INTERLEAVED_WEIGHTED_ROUND_ROBIN:return new(Z.bind(s))(t,r);default:throw new Error(`Worker choice strategy '${e}' is not valid`)}})(e,t,this,s))}removeWorkerChoiceStrategy(e){return this.workerChoiceStrategies.delete(e)}}class de extends Array{size;constructor(e=385,...t){super(),this.checkSize(e),this.size=e,arguments.length>1&&this.push(...t)}push(...e){const t=super.push(...e);return t>this.size&&super.splice(0,t-this.size),this.length}unshift(...e){return super.unshift(...e)>this.size&&super.splice(this.size,e.length),this.length}concat(...e){const t=super.concat(e);return t.size=this.size,t.length>t.size&&t.splice(0,t.length-t.size),t}splice(e,t,...s){let r=[];if(arguments.length>=3&&null!=t){if(r=super.splice(e,t,...s),this.length>this.size){const e=super.splice(0,this.length-this.size);r=new de(r.length+e.length,...r,...e)}}else r=2===arguments.length?super.splice(e,t):super.splice(e);return r}resize(e){if(this.checkSize(e),0===e)this.length=0;else if(e<this.size)for(let t=e;t<this.size;t++)super.pop();this.size=e}empty(){return 0===this.length}full(){return this.length===this.size}checkSize(e){if(!Number.isSafeInteger(e))throw new TypeError(`Invalid circular array size: ${e} is not a safe integer`);if(e<0)throw new RangeError(`Invalid circular array size: ${e} < 0`)}}class le{nodeArray;k;size;maxSize;get buckets(){return this.k===1/0?1:Math.trunc(this.nodeArray.length/this.k)}constructor(e=1/0){if(e!==1/0&&!Number.isSafeInteger(e))throw new TypeError("k must be an integer");if(e<1)throw new RangeError("k must be greater than or equal to 1");this.k=e,this.clear()}enqueue(e,t){t=t??0;let s=!1;for(let r=this.k===1/0?0:this.buckets*this.k;r<this.nodeArray.length;r++)if(this.nodeArray[r].priority>t){this.nodeArray.splice(r,0,{data:e,priority:t}),s=!0;break}return s||this.nodeArray.push({data:e,priority:t}),this.incrementSize()}dequeue(e=0){if(this.k!==1/0&&e>0)for(;e>0;){const t=e*this.k;if(null!=this.nodeArray[t])return--this.size,this.nodeArray.splice(t,1)[0].data;--e}return this.size>0&&--this.size,this.nodeArray.shift()?.data}peekFirst(){return this.nodeArray[0]?.data}peekLast(){return this.nodeArray[this.nodeArray.length-1]?.data}clear(){this.nodeArray=[],this.size=0,this.maxSize=0}[Symbol.iterator](){let e=0;return{next:()=>{if(e>=this.nodeArray.length)return{value:void 0,done:!0};const t=this.nodeArray[e].data;return e++,{value:t,done:!1}}}}incrementSize(){return++this.size,this.size>this.maxSize&&(this.maxSize=this.size),this.size}}class ge extends m{worker;info;usage;strategyData;messageChannel;tasksQueueBackPressureSize;tasksQueue;setBackPressureFlag;taskFunctionsUsage;constructor(t,s,r){super(),((e,t,s)=>{if(null==e)throw new TypeError("Cannot construct a worker node without a worker type");if(!Object.values(M).includes(e))throw new TypeError(`Cannot construct a worker node with an invalid worker type '${e}'`);if(A(t),null==s)throw new TypeError("Cannot construct a worker node without worker node options");if(!x(s))throw new TypeError("Cannot construct a worker node with invalid options: must be a plain object");if(null==s.tasksQueueBackPressureSize)throw new TypeError("Cannot construct a worker node without a tasks queue back pressure size option");if(!Number.isSafeInteger(s.tasksQueueBackPressureSize))throw new TypeError("Cannot construct a worker node with a tasks queue back pressure size option that is not an integer");if(s.tasksQueueBackPressureSize<=0)throw new RangeError("Cannot construct a worker node with a tasks queue back pressure size option that is not a positive integer");if(null==s.tasksQueueBucketSize)throw new TypeError("Cannot construct a worker node without a tasks queue bucket size option");if(!Number.isSafeInteger(s.tasksQueueBucketSize))throw new TypeError("Cannot construct a worker node with a tasks queue bucket size option that is not an integer");if(s.tasksQueueBucketSize<=0)throw new RangeError("Cannot construct a worker node with a tasks queue bucket size option that is not a positive integer")})(t,s,r),this.worker=((t,s,r)=>{switch(t){case M.thread:return new i(s,{env:o,...r.workerOptions});case M.cluster:return e.fork(r.env);default:throw new Error(`Unknown worker type '${t}'`)}})(t,s,{env:r.env,workerOptions:r.workerOptions}),this.info=this.initWorkerInfo(this.worker),this.usage=this.initWorkerUsage(),this.info.type===M.thread&&(this.messageChannel=new n),this.tasksQueueBackPressureSize=r.tasksQueueBackPressureSize,this.tasksQueue=new le(r.tasksQueueBucketSize),this.setBackPressureFlag=!1,this.taskFunctionsUsage=new Map}tasksQueueSize(){return this.tasksQueue.size}enqueueTask(e){const t=this.tasksQueue.enqueue(e,e.priority);return this.setBackPressureFlag||!this.hasBackPressure()||this.info.backPressure||(this.setBackPressureFlag=!0,this.info.backPressure=!0,this.emit("backPressure",{workerId:this.info.id}),this.setBackPressureFlag=!1),t}dequeueTask(e){const t=this.tasksQueue.dequeue(e);return this.setBackPressureFlag||this.hasBackPressure()||!this.info.backPressure||(this.setBackPressureFlag=!0,this.info.backPressure=!1,this.setBackPressureFlag=!1),t}dequeueLastPrioritizedTask(){return this.dequeueTask(this.tasksQueue.buckets+1)}clearTasksQueue(){this.tasksQueue.clear()}hasBackPressure(){return this.tasksQueue.size>=this.tasksQueueBackPressureSize}async terminate(){const e=new Promise((e=>{this.registerOnceWorkerEventHandler("exit",(()=>{e()}))}));switch(this.closeMessageChannel(),this.removeAllListeners(),this.info.type){case M.thread:this.worker.unref?.(),await(this.worker.terminate?.());break;case M.cluster:this.registerOnceWorkerEventHandler("disconnect",(()=>{this.worker.kill?.()})),this.worker.disconnect?.()}await e}registerWorkerEventHandler(e,t){this.worker.on(e,t)}registerOnceWorkerEventHandler(e,t){this.worker.once(e,t)}getTaskFunctionWorkerUsage(e){if(!Array.isArray(this.info.taskFunctionsProperties))throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function properties list is not yet defined`);if(Array.isArray(this.info.taskFunctionsProperties)&&this.info.taskFunctionsProperties.length<3)throw new Error(`Cannot get task function worker usage for task function name '${e}' when task function properties list has less than 3 elements`);return e===T&&(e=this.info.taskFunctionsProperties[1].name),this.taskFunctionsUsage.has(e)||this.taskFunctionsUsage.set(e,this.initTaskFunctionWorkerUsage(e)),this.taskFunctionsUsage.get(e)}deleteTaskFunctionWorkerUsage(e){return this.taskFunctionsUsage.delete(e)}closeMessageChannel(){null!=this.messageChannel&&(this.messageChannel.port1.unref(),this.messageChannel.port2.unref(),this.messageChannel.port1.close(),this.messageChannel.port2.close(),delete this.messageChannel)}initWorkerInfo(e){return{id:G(e),type:V(e),dynamic:!1,ready:!1,stealing:!1,backPressure:!1}}initWorkerUsage(){const e=()=>this.tasksQueue.size,t=()=>this.tasksQueue.maxSize;return{tasks:{executed:0,executing:0,get queued(){return e()},get maxQueued(){return t()},sequentiallyStolen:0,stolen:0,failed:0},runTime:{history:new de},waitTime:{history:new de},elu:{idle:{history:new de},active:{history:new de}}}}initTaskFunctionWorkerUsage(e){const t=()=>{let t=0;for(const s of this.tasksQueue)(s.name===T&&e===this.info.taskFunctionsProperties[1].name||s.name!==T&&e===s.name)&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},sequentiallyStolen:0,stolen:0,failed:0},runTime:{history:new de},waitTime:{history:new de},elu:{idle:{history:new de},active:{history:new de}}}}}class me{minimumNumberOfWorkers;filePath;opts;maximumNumberOfWorkers;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategiesContext;taskFunctions;started;starting;destroying;startingMinimumNumberOfWorkers;readyEventEmitted;startTimestamp;constructor(e,t,s,r){if(this.minimumNumberOfWorkers=e,this.filePath=t,this.opts=s,this.maximumNumberOfWorkers=r,!this.isMain())throw new Error("Cannot start a pool from a worker with the same type as the pool");this.checkPoolType(),A(this.filePath),this.checkMinimumNumberOfWorkers(this.minimumNumberOfWorkers),this.checkPoolOptions(this.opts),this.chooseWorkerNode=this.chooseWorkerNode.bind(this),this.executeTask=this.executeTask.bind(this),this.enqueueTask=this.enqueueTask.bind(this),!0===this.opts.enableEvents&&this.initEventEmitter(),this.workerChoiceStrategiesContext=new ce(this,[this.opts.workerChoiceStrategy],this.opts.workerChoiceStrategyOptions),this.setupHook(),this.taskFunctions=new Map,this.started=!1,this.starting=!1,this.destroying=!1,this.readyEventEmitted=!1,this.startingMinimumNumberOfWorkers=!1,!0===this.opts.startWorkers&&this.start()}checkPoolType(){if(this.type===y.fixed&&null!=this.maximumNumberOfWorkers)throw new Error("Cannot instantiate a fixed pool with a maximum number of workers specified at initialization")}checkMinimumNumberOfWorkers(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===y.fixed&&0===e)throw new RangeError("Cannot instantiate a fixed pool with zero worker")}checkPoolOptions(e){if(!x(e))throw new TypeError("Invalid pool options: must be a plain object");this.opts.startWorkers=e.startWorkers??!0,B(e.workerChoiceStrategy),this.opts.workerChoiceStrategy=e.workerChoiceStrategy??R.ROUND_ROBIN,this.checkValidWorkerChoiceStrategyOptions(e.workerChoiceStrategyOptions),null!=e.workerChoiceStrategyOptions&&(this.opts.workerChoiceStrategyOptions=e.workerChoiceStrategyOptions),this.opts.restartWorkerOnError=e.restartWorkerOnError??!0,this.opts.enableEvents=e.enableEvents??!0,this.opts.enableTasksQueue=e.enableTasksQueue??!1,this.opts.enableTasksQueue&&(D(e.tasksQueueOptions),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e.tasksQueueOptions))}checkValidWorkerChoiceStrategyOptions(e){if(null!=e&&!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.maximumNumberOfWorkers??this.minimumNumberOfWorkers))throw new Error("Invalid worker choice strategy options: must have a weight for each worker node");if(null!=e?.measurement&&!Object.values(z).includes(e.measurement))throw new Error(`Invalid worker choice strategy options: invalid measurement '${e.measurement}'`)}initEventEmitter(){this.emitter=new p({name:`poolifier:${this.type}-${this.worker}-pool`})}get info(){return{version:"4.0.4",type:this.type,worker:this.worker,started:this.started,ready:this.ready,defaultStrategy:this.opts.workerChoiceStrategy,strategyRetries:this.workerChoiceStrategiesContext?.retriesCount??0,minSize:this.minimumNumberOfWorkers,maxSize:this.maximumNumberOfWorkers??this.minimumNumberOfWorkers,...!0===this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements().runTime.aggregate&&this.workerChoiceStrategiesContext.getTaskStatisticsRequirements().waitTime.aggregate&&{utilization:v(this.utilization)},workerNodes:this.workerNodes.length,idleWorkerNodes:this.workerNodes.reduce(((e,t)=>0===t.usage.tasks.executing?e+1:e),0),...!0===this.opts.enableTasksQueue&&{stealingWorkerNodes:this.workerNodes.reduce(((e,t)=>t.info.stealing?e+1:e),0)},busyWorkerNodes:this.workerNodes.reduce(((e,t,s)=>this.isWorkerNodeBusy(s)?e+1:e),0),executedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executed),0),executingTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executing),0),...!0===this.opts.enableTasksQueue&&{queuedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.queued),0)},...!0===this.opts.enableTasksQueue&&{maxQueuedTasks:this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks.maxQueued??0)),0)},...!0===this.opts.enableTasksQueue&&{backPressure:this.hasBackPressure()},...!0===this.opts.enableTasksQueue&&{stolenTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.stolen),0)},failedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.failed),0),...!0===this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements().runTime.aggregate&&{runTime:{minimum:v(O(...this.workerNodes.map((e=>e.usage.runTime.minimum??1/0)))),maximum:v(I(...this.workerNodes.map((e=>e.usage.runTime.maximum??-1/0)))),...this.workerChoiceStrategiesContext.getTaskStatisticsRequirements().runTime.average&&{average:v(S(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))},...this.workerChoiceStrategiesContext.getTaskStatisticsRequirements().runTime.median&&{median:v(E(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.runTime.history)),[])))}}},...!0===this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:v(O(...this.workerNodes.map((e=>e.usage.waitTime.minimum??1/0)))),maximum:v(I(...this.workerNodes.map((e=>e.usage.waitTime.maximum??-1/0)))),...this.workerChoiceStrategiesContext.getTaskStatisticsRequirements().waitTime.average&&{average:v(S(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.waitTime.history)),[])))},...this.workerChoiceStrategiesContext.getTaskStatisticsRequirements().waitTime.median&&{median:v(E(this.workerNodes.reduce(((e,t)=>e.concat(t.usage.waitTime.history)),[])))}}}}}get ready(){return!this.empty&&this.workerNodes.reduce(((e,t)=>!t.info.dynamic&&t.info.ready?e+1:e),0)>=this.minimumNumberOfWorkers}get empty(){return 0===this.minimumNumberOfWorkers&&0===this.workerNodes.length}get utilization(){if(null==this.startTimestamp)return 0;const e=(w.now()-this.startTimestamp)*(this.maximumNumberOfWorkers??this.minimumNumberOfWorkers);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)throw new Error("Worker message received without worker id");if(-1===this.getWorkerNodeKeyByWorkerId(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKeyByWorkerId(e){return this.workerNodes.findIndex((t=>t.info.id===e))}setWorkerChoiceStrategy(e,t){let s=!1;if(B(e),null!=t&&(s=!this.setWorkerChoiceStrategyOptions(t)),e!==this.opts.workerChoiceStrategy&&(this.opts.workerChoiceStrategy=e,this.workerChoiceStrategiesContext?.setDefaultWorkerChoiceStrategy(this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),s=!0),s){this.workerChoiceStrategiesContext?.syncWorkerChoiceStrategies(this.getWorkerWorkerChoiceStrategies(),this.opts.workerChoiceStrategyOptions);for(const e of this.workerNodes.keys())this.sendStatisticsMessageToWorker(e)}}setWorkerChoiceStrategyOptions(e){if(this.checkValidWorkerChoiceStrategyOptions(e),null!=e){this.opts.workerChoiceStrategyOptions=e,this.workerChoiceStrategiesContext?.setOptions(this.opts.workerChoiceStrategyOptions),this.workerChoiceStrategiesContext?.syncWorkerChoiceStrategies(this.getWorkerWorkerChoiceStrategies(),this.opts.workerChoiceStrategyOptions);for(const e of this.workerNodes.keys())this.sendStatisticsMessageToWorker(e);return!0}return!1}enableTasksQueue(e,t){!0!==this.opts.enableTasksQueue||e||(this.unsetTaskStealing(),this.unsetTasksStealingOnBackPressure(),this.flushTasksQueues()),this.opts.enableTasksQueue=e,this.setTasksQueueOptions(t)}setTasksQueueOptions(e){!0===this.opts.enableTasksQueue?(D(e),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e),this.setTasksQueueSize(this.opts.tasksQueueOptions.size),!0===this.opts.tasksQueueOptions.taskStealing?(this.unsetTaskStealing(),this.setTaskStealing()):this.unsetTaskStealing(),!0===this.opts.tasksQueueOptions.tasksStealingOnBackPressure?(this.unsetTasksStealingOnBackPressure(),this.setTasksStealingOnBackPressure()):this.unsetTasksStealingOnBackPressure()):null!=this.opts.tasksQueueOptions&&delete this.opts.tasksQueueOptions}buildTasksQueueOptions(e){return{...K(this.maximumNumberOfWorkers??this.minimumNumberOfWorkers),...e}}setTasksQueueSize(e){for(const t of this.workerNodes)t.tasksQueueBackPressureSize=e}setTaskStealing(){for(const e of this.workerNodes.keys())this.workerNodes[e].on("idle",this.handleWorkerNodeIdleEvent)}unsetTaskStealing(){for(const e of this.workerNodes.keys())this.workerNodes[e].off("idle",this.handleWorkerNodeIdleEvent)}setTasksStealingOnBackPressure(){for(const e of this.workerNodes.keys())this.workerNodes[e].on("backPressure",this.handleWorkerNodeBackPressureEvent)}unsetTasksStealingOnBackPressure(){for(const e of this.workerNodes.keys())this.workerNodes[e].off("backPressure",this.handleWorkerNodeBackPressureEvent)}get full(){return this.workerNodes.length>=(this.maximumNumberOfWorkers??this.minimumNumberOfWorkers)}internalBusy(){return!0===this.opts.enableTasksQueue?-1===this.workerNodes.findIndex((e=>e.info.ready&&e.usage.tasks.executing<this.opts.tasksQueueOptions.concurrency)):-1===this.workerNodes.findIndex((e=>e.info.ready&&0===e.usage.tasks.executing))}isWorkerNodeBusy(e){return!0===this.opts.enableTasksQueue?this.workerNodes[e].usage.tasks.executing>=this.opts.tasksQueueOptions.concurrency:this.workerNodes[e].usage.tasks.executing>0}async sendTaskFunctionOperationToWorker(e,t){return await new Promise(((s,r)=>{const i=t=>{this.checkMessageWorkerId(t);const o=this.getWorkerInfo(e)?.id;null!=t.taskFunctionOperationStatus&&t.workerId===o&&(t.taskFunctionOperationStatus?s(!0):r(new Error(`Task function operation '${t.taskFunctionOperation}' failed on worker ${t.workerId} with error: '${t.workerError?.message}'`)),this.deregisterWorkerMessageListener(this.getWorkerNodeKeyByWorkerId(t.workerId),i))};this.registerWorkerMessageListener(e,i),this.sendToWorker(e,t)}))}async sendTaskFunctionOperationToWorkers(e){return await new Promise(((t,s)=>{const r=new Array,i=e=>{if(this.checkMessageWorkerId(e),null!=e.taskFunctionOperationStatus&&(r.push(e),r.length===this.workerNodes.length)){if(r.every((e=>!0===e.taskFunctionOperationStatus)))t(!0);else if(r.some((e=>!1===e.taskFunctionOperationStatus))){const t=r.find((e=>!1===e.taskFunctionOperationStatus));s(new Error(`Task function operation '${e.taskFunctionOperation}' failed on worker ${t?.workerId} with error: '${t?.workerError?.message}'`))}this.deregisterWorkerMessageListener(this.getWorkerNodeKeyByWorkerId(e.workerId),i)}};for(const t of this.workerNodes.keys())this.registerWorkerMessageListener(t,i),this.sendToWorker(t,e)}))}hasTaskFunction(e){return this.listTaskFunctionsProperties().some((t=>t.name===e))}async addTaskFunction(e,t){if("string"!=typeof e)throw new TypeError("name argument must be a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("name argument must not be an empty string");if("function"==typeof t&&(t={taskFunction:t}),"function"!=typeof t.taskFunction)throw new TypeError("taskFunction property must be a function");U(t.priority),B(t.strategy);const s=await this.sendTaskFunctionOperationToWorkers({taskFunctionOperation:"add",taskFunctionProperties:P(e,t),taskFunction:t.taskFunction.toString()});this.taskFunctions.set(e,t),this.workerChoiceStrategiesContext?.syncWorkerChoiceStrategies(this.getWorkerWorkerChoiceStrategies());for(const e of this.workerNodes.keys())this.sendStatisticsMessageToWorker(e);return s}async removeTaskFunction(e){if(!this.taskFunctions.has(e))throw new Error("Cannot remove a task function not handled on the pool side");const t=await this.sendTaskFunctionOperationToWorkers({taskFunctionOperation:"remove",taskFunctionProperties:P(e,this.taskFunctions.get(e))});for(const t of this.workerNodes)t.deleteTaskFunctionWorkerUsage(e);this.taskFunctions.delete(e),this.workerChoiceStrategiesContext?.syncWorkerChoiceStrategies(this.getWorkerWorkerChoiceStrategies());for(const e of this.workerNodes.keys())this.sendStatisticsMessageToWorker(e);return t}listTaskFunctionsProperties(){for(const e of this.workerNodes)if(Array.isArray(e.info.taskFunctionsProperties)&&e.info.taskFunctionsProperties.length>0)return e.info.taskFunctionsProperties;return[]}getTaskFunctionWorkerWorkerChoiceStrategy=e=>{if(null!=e)return this.listTaskFunctionsProperties().find((t=>t.name===e))?.strategy};getWorkerNodeTaskFunctionPriority=(e,t)=>{if(null!=t)return this.getWorkerInfo(e)?.taskFunctionsProperties?.find((e=>e.name===t))?.priority};getWorkerWorkerChoiceStrategies=()=>new Set([this.opts.workerChoiceStrategy,...this.listTaskFunctionsProperties().map((e=>e.strategy)).filter((e=>null!=e))]);async setDefaultTaskFunction(e){return await this.sendTaskFunctionOperationToWorkers({taskFunctionOperation:"default",taskFunctionProperties:P(e,this.taskFunctions.get(e))})}shallExecuteTask(e){return 0===this.tasksQueueSize(e)&&this.workerNodes[e].usage.tasks.executing<this.opts.tasksQueueOptions.concurrency}async execute(e,t,s){return await new Promise(((r,i)=>{if(!this.started)return void i(new Error("Cannot execute a task on not started pool"));if(this.destroying)return void i(new Error("Cannot execute a task on destroying pool"));if(null!=t&&"string"!=typeof t)return void i(new TypeError("name argument must be a string"));if(null!=t&&"string"==typeof t&&0===t.trim().length)return void i(new TypeError("name argument must not be an empty string"));if(null!=s&&!Array.isArray(s))return void i(new TypeError("transferList argument must be an array"));const o=w.now(),n=this.getTaskFunctionWorkerWorkerChoiceStrategy(t),a=this.chooseWorkerNode(n),u={name:t??T,data:e??{},priority:this.getWorkerNodeTaskFunctionPriority(a,t),strategy:n,transferList:s,timestamp:o,taskId:c()};this.promiseResponseMap.set(u.taskId,{resolve:r,reject:i,workerNodeKey:a,...null!=this.emitter&&{asyncResource:new g("poolifier:task",{triggerAsyncId:this.emitter.asyncId,requireManualDestroy:!0})}}),!1===this.opts.enableTasksQueue||!0===this.opts.enableTasksQueue&&this.shallExecuteTask(a)?this.executeTask(a,u):this.enqueueTask(a,u)}))}startMinimumNumberOfWorkers(e=!1){for(this.startingMinimumNumberOfWorkers=!0;this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.minimumNumberOfWorkers;){const t=this.createAndSetupWorkerNode();e&&this.initWorkerNodeUsage(this.workerNodes[t])}this.startingMinimumNumberOfWorkers=!1}start(){if(this.started)throw new Error("Cannot start an already started pool");if(this.starting)throw new Error("Cannot start an already starting pool");if(this.destroying)throw new Error("Cannot start a destroying pool");this.starting=!0,this.startMinimumNumberOfWorkers(),this.startTimestamp=w.now(),this.starting=!1,this.started=!0}async destroy(){if(!this.started)throw new Error("Cannot destroy an already destroyed pool");if(this.starting)throw new Error("Cannot destroy an starting pool");if(this.destroying)throw new Error("Cannot destroy an already destroying pool");this.destroying=!0,await Promise.all(this.workerNodes.map((async(e,t)=>{await this.destroyWorkerNode(t)}))),this.emitter?.emit(f.destroy,this.info),this.emitter?.emitDestroy(),this.readyEventEmitted=!1,delete this.startTimestamp,this.destroying=!1,this.started=!1}async sendKillMessageToWorker(e){await new Promise(((t,s)=>{if(null==this.workerNodes[e])return void t();this.registerWorkerMessageListener(e,(e=>{this.checkMessageWorkerId(e),"success"===e.kill?t():"failure"===e.kill&&s(new Error(`Kill message handling failed on worker ${e.workerId}`))})),this.sendToWorker(e,{kill:!0})}))}async destroyWorkerNode(e){this.flagWorkerNodeAsNotReady(e);const t=this.flushTasksQueue(e),s=this.workerNodes[e];await(async(e,t,s,r)=>await new Promise((i=>{let o=0;0!==s?(e.on(t,(()=>{++o,o===s&&i(o)})),r>=0&&setTimeout((()=>{i(o)}),r)):i(o)})))(s,"taskFinished",t,this.opts.tasksQueueOptions?.tasksFinishedTimeout??K(this.maximumNumberOfWorkers??this.minimumNumberOfWorkers).tasksFinishedTimeout),await this.sendKillMessageToWorker(e),await s.terminate()}setupHook(){}beforeTaskExecutionHook(e,t){if(null!=this.workerNodes[e]?.usage){const s=this.workerNodes[e].usage;++s.tasks.executing,H(this.workerChoiceStrategiesContext,s,t)}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name)){const s=this.workerNodes[e].getTaskFunctionWorkerUsage(t.name);++s.tasks.executing,H(this.workerChoiceStrategiesContext,s,t)}}afterTaskExecutionHook(e,t){let s=!1;if(null!=this.workerNodes[e]?.usage){const r=this.workerNodes[e].usage;_(r,t),$(this.workerChoiceStrategiesContext,r,t),j(this.workerChoiceStrategiesContext,r,t),s=!0}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance.name)){const r=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance.name);_(r,t),$(this.workerChoiceStrategiesContext,r,t),j(this.workerChoiceStrategiesContext,r,t),s=!0}s&&this.workerChoiceStrategiesContext?.update(e)}shallUpdateTaskFunctionWorkerUsage(e){const t=this.getWorkerInfo(e);return null!=t&&Array.isArray(t.taskFunctionsProperties)&&t.taskFunctionsProperties.length>2}chooseWorkerNode(e){if(this.shallCreateDynamicWorker()){const e=this.createAndSetupDynamicWorkerNode();if(!0===this.workerChoiceStrategiesContext?.getPolicy().dynamicWorkerUsage)return e}return this.workerChoiceStrategiesContext.execute(e)}initWorkerNodeUsage(e){!0===this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements().runTime.aggregate&&(e.usage.runTime.aggregate=O(...this.workerNodes.map((e=>e.usage.runTime.aggregate??1/0)))),!0===this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements().waitTime.aggregate&&(e.usage.waitTime.aggregate=O(...this.workerNodes.map((e=>e.usage.waitTime.aggregate??1/0)))),!0===this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements().elu.aggregate&&(e.usage.elu.active.aggregate=O(...this.workerNodes.map((e=>e.usage.elu.active.aggregate??1/0))))}createAndSetupWorkerNode(){const e=this.createWorkerNode();e.registerWorkerEventHandler("online",this.opts.onlineHandler??W),e.registerWorkerEventHandler("message",this.opts.messageHandler??W),e.registerWorkerEventHandler("error",this.opts.errorHandler??W),e.registerOnceWorkerEventHandler("error",(t=>{e.info.ready=!1,this.emitter?.emit(f.error,t),this.started&&!this.destroying&&!0===this.opts.restartWorkerOnError&&(e.info.dynamic?this.createAndSetupDynamicWorkerNode():this.startingMinimumNumberOfWorkers||this.startMinimumNumberOfWorkers(!0)),this.started&&!this.destroying&&!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(this.workerNodes.indexOf(e)),e?.terminate().catch((e=>{this.emitter?.emit(f.error,e)}))})),e.registerWorkerEventHandler("exit",this.opts.exitHandler??W),e.registerOnceWorkerEventHandler("exit",(()=>{this.removeWorkerNode(e),!this.started||this.startingMinimumNumberOfWorkers||this.destroying||this.startMinimumNumberOfWorkers(!0)}));const t=this.addWorkerNode(e);return this.afterWorkerNodeSetup(t),t}createAndSetupDynamicWorkerNode(){const e=this.createAndSetupWorkerNode();if(this.registerWorkerMessageListener(e,(e=>{this.checkMessageWorkerId(e);const t=this.getWorkerNodeKeyByWorkerId(e.workerId),s=this.workerNodes[t]?.usage;(C(Y.HARD,e.kill)||C(Y.SOFT,e.kill)&&(!1===this.opts.enableTasksQueue&&0===s.tasks.executing||!0===this.opts.enableTasksQueue&&0===s.tasks.executing&&0===this.tasksQueueSize(t)))&&(this.flagWorkerNodeAsNotReady(t),this.destroyWorkerNode(t).catch((e=>{this.emitter?.emit(f.error,e)})))})),this.sendToWorker(e,{checkActive:!0}),this.taskFunctions.size>0)for(const[t,s]of this.taskFunctions)this.sendTaskFunctionOperationToWorker(e,{taskFunctionOperation:"add",taskFunctionProperties:P(t,s),taskFunction:s.taskFunction.toString()}).catch((e=>{this.emitter?.emit(f.error,e)}));const t=this.workerNodes[e];return t.info.dynamic=!0,!0!==this.workerChoiceStrategiesContext?.getPolicy().dynamicWorkerReady&&!0!==this.workerChoiceStrategiesContext?.getPolicy().dynamicWorkerUsage||(t.info.ready=!0),this.initWorkerNodeUsage(t),this.checkAndEmitDynamicWorkerCreationEvents(),e}afterWorkerNodeSetup(e){this.registerWorkerMessageListener(e,this.workerMessageListener),this.sendStartupMessageToWorker(e),this.sendStatisticsMessageToWorker(e),!0===this.opts.enableTasksQueue&&(!0===this.opts.tasksQueueOptions?.taskStealing&&this.workerNodes[e].on("idle",this.handleWorkerNodeIdleEvent),!0===this.opts.tasksQueueOptions?.tasksStealingOnBackPressure&&this.workerNodes[e].on("backPressure",this.handleWorkerNodeBackPressureEvent))}sendStatisticsMessageToWorker(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements().runTime.aggregate??!1,elu:this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements().elu.aggregate??!1}})}cannotStealTask(){return this.workerNodes.length<=1||0===this.info.queuedTasks}handleTask(e,t){this.shallExecuteTask(e)?this.executeTask(e,t):this.enqueueTask(e,t)}redistributeQueuedTasks(e){if(-1!==e&&!this.cannotStealTask())for(;this.tasksQueueSize(e)>0;){const t=this.workerNodes.reduce(((e,t,s,r)=>t.info.ready&&t.usage.tasks.queued<r[e].usage.tasks.queued?s:e),0);this.handleTask(t,this.dequeueTask(e))}}updateTaskStolenStatisticsWorkerUsage(e,t){const s=this.workerNodes[e];if(null!=s?.usage&&++s.usage.tasks.stolen,this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=s.getTaskFunctionWorkerUsage(t)){++s.getTaskFunctionWorkerUsage(t).tasks.stolen}}updateTaskSequentiallyStolenStatisticsWorkerUsage(e){const t=this.workerNodes[e];null!=t?.usage&&++t.usage.tasks.sequentiallyStolen}updateTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(e,t){const s=this.workerNodes[e];if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=s.getTaskFunctionWorkerUsage(t)){++s.getTaskFunctionWorkerUsage(t).tasks.sequentiallyStolen}}resetTaskSequentiallyStolenStatisticsWorkerUsage(e){const t=this.workerNodes[e];null!=t?.usage&&(t.usage.tasks.sequentiallyStolen=0)}resetTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(e,t){const s=this.workerNodes[e];if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=s.getTaskFunctionWorkerUsage(t)){s.getTaskFunctionWorkerUsage(t).tasks.sequentiallyStolen=0}}handleWorkerNodeIdleEvent=(e,t)=>{const{workerNodeKey:s}=e;if(null==s)throw new Error("WorkerNode event detail 'workerNodeKey' property must be defined");const r=this.getWorkerInfo(s);if(this.cannotStealTask()||(this.info.stealingWorkerNodes??0)>Math.floor(this.workerNodes.length/2))return void(null!=r&&null!=t&&(r.stealing=!1));const i=this.workerNodes[s].usage.tasks;if(null!=r&&null!=t&&i.sequentiallyStolen>0&&(i.executing>0||this.tasksQueueSize(s)>0)){r.stealing=!1;for(const e of r.taskFunctionsProperties)this.resetTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(s,e.name);return void this.resetTaskSequentiallyStolenStatisticsWorkerUsage(s)}if(null==r)throw new Error(`Worker node with key '${s}' not found in pool`);r.stealing=!0;const o=this.workerNodeStealTask(s);if(this.shallUpdateTaskFunctionWorkerUsage(s)&&null!=o){const e=this.workerNodes[s].getTaskFunctionWorkerUsage(o.name).tasks;0===e.sequentiallyStolen||null!=t&&t.name===o.name&&e.sequentiallyStolen>0?this.updateTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(s,o.name):this.resetTaskSequentiallyStolenStatisticsTaskFunctionWorkerUsage(s,o.name)}(async e=>{await new Promise((t=>{setTimeout(t,e)}))})(((e=0,t=100)=>{const s=Math.pow(2,e)*t;return s+.2*s*F()})(i.sequentiallyStolen)).then((()=>{this.handleWorkerNodeIdleEvent(e,o)})).catch((e=>{this.emitter?.emit(f.error,e)}))};workerNodeStealTask=e=>{const t=this.workerNodes.slice().sort(((e,t)=>t.usage.tasks.queued-e.usage.tasks.queued)).find(((t,s)=>t.info.ready&&!t.info.stealing&&s!==e&&t.usage.tasks.queued>0));if(null!=t){const s=t.dequeueLastPrioritizedTask();return this.handleTask(e,s),this.updateTaskSequentiallyStolenStatisticsWorkerUsage(e),this.updateTaskStolenStatisticsWorkerUsage(e,s.name),s}};handleWorkerNodeBackPressureEvent=e=>{if(this.cannotStealTask()||this.hasBackPressure()||(this.info.stealingWorkerNodes??0)>Math.floor(this.workerNodes.length/2))return;const{workerId:t}=e;if(this.opts.tasksQueueOptions.size<=1)return;const s=this.workerNodes[this.getWorkerNodeKeyByWorkerId(t)],r=this.workerNodes.slice().sort(((e,t)=>e.usage.tasks.queued-t.usage.tasks.queued));for(const[e,i]of r.entries())if(s.usage.tasks.queued>0&&i.info.ready&&!i.info.stealing&&i.info.id!==t&&i.usage.tasks.queued<this.opts.tasksQueueOptions.size-1){const t=this.getWorkerInfo(e);if(null==t)throw new Error(`Worker node with key '${e}' not found in pool`);t.stealing=!0;const r=s.dequeueLastPrioritizedTask();this.handleTask(e,r),this.updateTaskStolenStatisticsWorkerUsage(e,r.name),t.stealing=!1}};workerMessageListener=e=>{this.checkMessageWorkerId(e);const{workerId:t,ready:s,taskId:r,taskFunctionsProperties:i}=e;if(null!=s&&null!=i)this.handleWorkerReadyResponse(e);else if(null!=i){const e=this.getWorkerNodeKeyByWorkerId(t),s=this.getWorkerInfo(e);null!=s&&(s.taskFunctionsProperties=i,this.sendStatisticsMessageToWorker(e))}else null!=r&&this.handleTaskExecutionResponse(e)};checkAndEmitReadyEvent(){!this.readyEventEmitted&&this.ready&&(this.emitter?.emit(f.ready,this.info),this.readyEventEmitted=!0)}handleWorkerReadyResponse(e){const{workerId:t,ready:s,taskFunctionsProperties:r}=e;if(null==s||!s)throw new Error(`Worker ${t} failed to initialize`);const i=this.getWorkerNodeKeyByWorkerId(t),o=this.workerNodes[i];o.info.ready=s,o.info.taskFunctionsProperties=r,this.sendStatisticsMessageToWorker(i),this.checkAndEmitReadyEvent()}handleTaskExecutionResponse(e){const{workerId:t,taskId:s,workerError:r,data:i}=e,o=this.promiseResponseMap.get(s);if(null!=o){const{resolve:n,reject:a,workerNodeKey:u,asyncResource:h}=o,k=this.workerNodes[u];if(null!=r?(this.emitter?.emit(f.taskError,r),null!=h?h.runInAsyncScope(a,this.emitter,r.message):a(r.message)):null!=h?h.runInAsyncScope(n,this.emitter,i):n(i),h?.emitDestroy(),this.afterTaskExecutionHook(u,e),this.promiseResponseMap.delete(s),k?.emit("taskFinished",s),!0===this.opts.enableTasksQueue&&!this.destroying&&null!=k){const e=k.usage.tasks;this.tasksQueueSize(u)>0&&e.executing<this.opts.tasksQueueOptions.concurrency&&this.executeTask(u,this.dequeueTask(u)),0===e.executing&&0===this.tasksQueueSize(u)&&0===e.sequentiallyStolen&&k.emit("idle",{workerId:t,workerNodeKey:u})}}}checkAndEmitTaskExecutionEvents(){this.busy&&this.emitter?.emit(f.busy,this.info)}checkAndEmitTaskQueuingEvents(){this.hasBackPressure()&&this.emitter?.emit(f.backPressure,this.info)}getWorkerInfo(e){return this.workerNodes[e]?.info}createWorkerNode(){const e=new ge(this.worker,this.filePath,{env:this.opts.env,workerOptions:this.opts.workerOptions,tasksQueueBackPressureSize:this.opts.tasksQueueOptions?.size??K(this.maximumNumberOfWorkers??this.minimumNumberOfWorkers).size,tasksQueueBucketSize:2*(this.maximumNumberOfWorkers??this.minimumNumberOfWorkers)});return this.starting&&(e.info.ready=!0),e}addWorkerNode(e){this.workerNodes.push(e);const t=this.workerNodes.indexOf(e);if(-1===t)throw new Error("Worker added not found in worker nodes");return t}checkAndEmitEmptyEvent(){this.empty&&(this.emitter?.emit(f.empty,this.info),this.readyEventEmitted=!1)}removeWorkerNode(e){const t=this.workerNodes.indexOf(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategiesContext?.remove(t)),this.checkAndEmitEmptyEvent()}flagWorkerNodeAsNotReady(e){const t=this.getWorkerInfo(e);null!=t&&(t.ready=!1)}hasBackPressure(){return!0===this.opts.enableTasksQueue&&-1===this.workerNodes.findIndex((e=>!e.hasBackPressure()))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(e,t,t.transferList),this.checkAndEmitTaskExecutionEvents()}enqueueTask(e,t){const s=this.workerNodes[e].enqueueTask(t);return this.checkAndEmitTaskQueuingEvents(),s}dequeueTask(e){return this.workerNodes[e].dequeueTask()}tasksQueueSize(e){return this.workerNodes[e].tasksQueueSize()}flushTasksQueue(e){let t=0;for(;this.tasksQueueSize(e)>0;)this.executeTask(e,this.dequeueTask(e)),++t;return this.workerNodes[e].clearTasksQueue(),t}flushTasksQueues(){for(const e of this.workerNodes.keys())this.flushTasksQueue(e)}}class pe extends me{constructor(e,t,s={},r){super(e,t,s,r)}setupHook(){e.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return e.isPrimary}sendToWorker(e,t){this.workerNodes[e]?.worker.send({...t,workerId:this.getWorkerInfo(e)?.id})}sendStartupMessageToWorker(e){this.sendToWorker(e,{ready:!1})}registerWorkerMessageListener(e,t){this.workerNodes[e].worker.on("message",t)}registerOnceWorkerMessageListener(e,t){this.workerNodes[e].worker.once("message",t)}deregisterWorkerMessageListener(e,t){this.workerNodes[e].worker.off("message",t)}shallCreateDynamicWorker(){return!1}checkAndEmitDynamicWorkerCreationEvents(){}get type(){return y.fixed}get worker(){return M.cluster}get busy(){return this.internalBusy()}}class we extends pe{constructor(e,t,s,r={}){super(e,s,r,t),Q(this.minimumNumberOfWorkers,this.maximumNumberOfWorkers)}shallCreateDynamicWorker(){return!this.full&&this.internalBusy()||this.empty}checkAndEmitDynamicWorkerCreationEvents(){this.full&&this.emitter?.emit(f.full,this.info)}get type(){return y.dynamic}get busy(){return this.full&&this.internalBusy()}}class ye extends me{constructor(e,t,s={},r){super(e,t,s,r)}isMain(){return a}sendToWorker(e,t,s){this.workerNodes[e]?.messageChannel?.port1.postMessage({...t,workerId:this.getWorkerInfo(e)?.id},s)}sendStartupMessageToWorker(e){const t=this.workerNodes[e],s=t.messageChannel.port2;t.worker.postMessage({ready:!1,workerId:this.getWorkerInfo(e)?.id,port:s},[s])}registerWorkerMessageListener(e,t){this.workerNodes[e].messageChannel?.port1.on("message",t)}registerOnceWorkerMessageListener(e,t){this.workerNodes[e].messageChannel?.port1.once("message",t)}deregisterWorkerMessageListener(e,t){this.workerNodes[e].messageChannel?.port1.off("message",t)}shallCreateDynamicWorker(){return!1}checkAndEmitDynamicWorkerCreationEvents(){}get type(){return y.fixed}get worker(){return M.thread}get busy(){return this.internalBusy()}}class fe extends ye{constructor(e,t,s,r={}){super(e,s,r,t),Q(this.minimumNumberOfWorkers,this.maximumNumberOfWorkers)}shallCreateDynamicWorker(){return!this.full&&this.internalBusy()||this.empty}checkAndEmitDynamicWorkerCreationEvents(){this.full&&this.emitter?.emit(f.full,this.info)}get type(){return y.dynamic}get busy(){return this.full&&this.internalBusy()}}const Te=(e,t)=>{if("string"!=typeof e)throw new TypeError("A taskFunctions parameter object key is not a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("A taskFunctions parameter object key is an empty string");if("function"!=typeof t.taskFunction)throw new TypeError(`taskFunction object 'taskFunction' property '${t.taskFunction}' is not a function`);U(t.priority),B(t.strategy)},We=e=>{if("string"!=typeof e)throw new TypeError("name parameter is not a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("name parameter is an empty string")},Ne=6e4,Se={killBehavior:Y.SOFT,maxInactiveTime:Ne,killHandler:W};class Ee{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,s,r=Se){if(this.isMain=e,this.mainWorker=t,this.opts=r,null==this.isMain)throw new Error("isMain parameter is mandatory");this.checkTaskFunctions(s),this.checkWorkerOptions(this.opts),this.isMain||this.getMainWorker().on("message",this.handleReadyMessage.bind(this))}checkWorkerOptions(e){(e=>{if(null!=e&&!x(e))throw new TypeError("opts worker options parameter is not a plain object");if(null!=e?.killBehavior&&!Object.values(Y).includes(e.killBehavior))throw new TypeError(`killBehavior option '${e.killBehavior}' is not valid`);if(null!=e?.maxInactiveTime&&!Number.isSafeInteger(e.maxInactiveTime))throw new TypeError("maxInactiveTime option is not an integer");if(null!=e?.maxInactiveTime&&e.maxInactiveTime<5)throw new TypeError("maxInactiveTime option is not a positive integer greater or equal than 5");if(null!=e?.killHandler&&"function"!=typeof e.killHandler)throw new TypeError("killHandler option is not a function")})(e),this.opts={...Se,...e}}checkTaskFunctions(e){if(null==e)throw new Error("taskFunctions parameter is mandatory");if(this.taskFunctions=new Map,"function"==typeof e){const t={taskFunction:e.bind(this)};this.taskFunctions.set(T,t),this.taskFunctions.set("string"==typeof e.name&&e.name.trim().length>0?e.name:"fn1",t)}else{if(!x(e))throw new TypeError("taskFunctions parameter is not a function or a plain object");{let t=!0;for(let[s,r]of Object.entries(e))"function"==typeof r&&(r={taskFunction:r}),Te(s,r),r.taskFunction=r.taskFunction.bind(this),t&&(this.taskFunctions.set(T,r),t=!1),this.taskFunctions.set(s,r);if(t)throw new Error("taskFunctions parameter object is empty")}}}hasTaskFunction(e){try{We(e)}catch(e){return{status:!1,error:e}}return{status:this.taskFunctions.has(e)}}addTaskFunction(e,t){try{if(We(e),e===T)throw new Error("Cannot add a task function with the default reserved name");return"function"==typeof t&&(t={taskFunction:t}),Te(e,t),t.taskFunction=t.taskFunction.bind(this),this.taskFunctions.get(e)===this.taskFunctions.get(T)&&this.taskFunctions.set(T,t),this.taskFunctions.set(e,t),this.sendTaskFunctionsPropertiesToMainWorker(),{status:!0}}catch(e){return{status:!1,error:e}}}removeTaskFunction(e){try{if(We(e),e===T)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(T))throw new Error("Cannot remove the task function used as the default task function");const t=this.taskFunctions.delete(e);return this.sendTaskFunctionsPropertiesToMainWorker(),{status:t}}catch(e){return{status:!1,error:e}}}listTaskFunctionsProperties(){let e=T;for(const[t,s]of this.taskFunctions)if(t!==T&&s===this.taskFunctions.get(T)){e=t;break}const t=[];for(const[s,r]of this.taskFunctions)s!==T&&s!==e&&t.push(P(s,r));return[P(T,this.taskFunctions.get(T)),P(e,this.taskFunctions.get(e)),...t]}setDefaultTaskFunction(e){try{if(We(e),e===T)throw new Error("Cannot set the default task function reserved name as the default task function");if(!this.taskFunctions.has(e))throw new Error("Cannot set the default task function to a non-existing task function");return this.taskFunctions.set(T,this.taskFunctions.get(e)),this.sendTaskFunctionsPropertiesToMainWorker(),{status:!0}}catch(e){return{status:!1,error:e}}}messageListener(e){this.checkMessageWorkerId(e);const{statistics:t,checkActive:s,taskFunctionOperation:r,taskId:i,data:o,kill:n}=e;null!=t?this.statistics=t:null!=s?s?this.startCheckActive():this.stopCheckActive():null!=r?this.handleTaskFunctionOperationMessage(e):null!=i&&null!=o?this.run(e):!0===n&&this.handleKillMessage(e)}handleTaskFunctionOperationMessage(e){const{taskFunctionOperation:t,taskFunctionProperties:s,taskFunction:r}=e;if(null==s)throw new Error("Cannot handle task function operation message without task function properties");let i;switch(t){case"add":i=this.addTaskFunction(s.name,{taskFunction:new Function(`return ${r}`)(),...null!=s.priority&&{priority:s.priority},...null!=s.strategy&&{strategy:s.strategy}});break;case"remove":i=this.removeTaskFunction(s.name);break;case"default":i=this.setDefaultTaskFunction(s.name);break;default:i={status:!1,error:new Error("Unknown task operation")}}this.sendToMainWorker({taskFunctionOperation:t,taskFunctionOperationStatus:i.status,taskFunctionProperties:s,...!i.status&&null!=i.error&&{workerError:{name:s.name,message:this.handleError(i.error)}}})}handleKillMessage(e){if(this.stopCheckActive(),b(this.opts.killHandler))this.opts.killHandler().then((()=>{this.sendToMainWorker({kill:"success"})})).catch((()=>{this.sendToMainWorker({kill:"failure"})}));else try{this.opts.killHandler?.(),this.sendToMainWorker({kill:"success"})}catch{this.sendToMainWorker({kill:"failure"})}}checkMessageWorkerId(e){if(null==e.workerId)throw new Error("Message worker id is not set");if(e.workerId!==this.id)throw new Error(`Message worker id ${e.workerId} does not match the worker id ${this.id}`)}startCheckActive(){this.lastTaskTimestamp=w.now(),this.activeInterval=setInterval(this.checkActive.bind(this),(this.opts.maxInactiveTime??Ne)/2)}stopCheckActive(){null!=this.activeInterval&&(clearInterval(this.activeInterval),delete this.activeInterval)}checkActive(){w.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??Ne)&&this.sendToMainWorker({kill:this.opts.killBehavior})}getMainWorker(){if(null==this.mainWorker)throw new Error("Main worker not set");return this.mainWorker}sendTaskFunctionsPropertiesToMainWorker(){this.sendToMainWorker({taskFunctionsProperties:this.listTaskFunctionsProperties()})}handleError(e){return e instanceof Error?e.message:e}run=e=>{const{name:t,taskId:s,data:r}=e,i=t??T;if(!this.taskFunctions.has(i))return void this.sendToMainWorker({workerError:{name:t,message:`Task function '${t}' not found`,data:r},taskId:s});const o=this.taskFunctions.get(i)?.taskFunction;b(o)?this.runAsync(o,e):this.runSync(o,e)};runSync=(e,t)=>{const{name:s,taskId:r,data:i}=t;try{let t=this.beginTaskPerformance(s);const o=e(i);t=this.endTaskPerformance(t),this.sendToMainWorker({data:o,taskPerformance:t,taskId:r})}catch(e){this.sendToMainWorker({workerError:{name:s,message:this.handleError(e),data:i},taskId:r})}finally{this.updateLastTaskTimestamp()}};runAsync=(e,t)=>{const{name:s,taskId:r,data:i}=t;let o=this.beginTaskPerformance(s);e(i).then((e=>{o=this.endTaskPerformance(o),this.sendToMainWorker({data:e,taskPerformance:o,taskId:r})})).catch((e=>{this.sendToMainWorker({workerError:{name:s,message:this.handleError(e),data:i},taskId:r})})).finally((()=>{this.updateLastTaskTimestamp()})).catch(W)};beginTaskPerformance(e){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set");return{name:e??T,timestamp:w.now(),...this.statistics.elu&&{elu:w.eventLoopUtilization()}}}endTaskPerformance(e){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set");return{...e,...this.statistics.runTime&&{runTime:w.now()-e.timestamp},...this.statistics.elu&&{elu:w.eventLoopUtilization(e.elu)}}}updateLastTaskTimestamp(){null!=this.activeInterval&&(this.lastTaskTimestamp=w.now())}}class ve extends Ee{constructor(t,s={}){super(e.isPrimary,e.worker,t,s)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready)try{this.getMainWorker().on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctionsProperties:this.listTaskFunctionsProperties()})}catch{this.sendToMainWorker({ready:!1,taskFunctionsProperties:this.listTaskFunctionsProperties()})}}get id(){return this.getMainWorker().id}sendToMainWorker=e=>{this.getMainWorker().send({...e,workerId:this.id})}}class xe extends Ee{port;constructor(e,t={}){super(a,u,e,t)}handleReadyMessage(e){if(e.workerId===this.id&&!1===e.ready&&null!=e.port)try{this.port=e.port,this.port.on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,taskFunctionsProperties:this.listTaskFunctionsProperties()})}catch{this.sendToMainWorker({ready:!1,taskFunctionsProperties:this.listTaskFunctionsProperties()})}}handleKillMessage(e){super.handleKillMessage(e),this.port?.unref(),this.port?.close()}get id(){return h}sendToMainWorker=e=>{this.port?.postMessage({...e,workerId:this.id})};handleError(e){return e}}export{ve as ClusterWorker,we as DynamicClusterPool,fe as DynamicThreadPool,pe as FixedClusterPool,ye as FixedThreadPool,Y as KillBehaviors,z as Measurements,f as PoolEvents,y as PoolTypes,xe as ThreadWorker,R as WorkerChoiceStrategies,M as WorkerTypes,N as availableParallelism};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|