poolifier
Version:
Fast and small Node.js Worker_Threads and Cluster Worker Pool
1 lines • 83.2 kB
JavaScript
"use strict";var e=require("node:cluster"),t=require("node:fs"),r=require("node:worker_threads"),s=require("node:crypto"),i=require("node:os"),o=require("node:async_hooks"),n=require("node:events"),a=require("node:perf_hooks");function u(e){var t=Object.create(null);return e&&Object.keys(e).forEach(function(r){if("default"!==r){var s=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,s.get?s:{enumerable:!0,get:function(){return e[r]}})}}),t.default=e,Object.freeze(t)}var h=u(i);const k=Object.freeze({dynamic:"dynamic",fixed:"fixed"}),d=Object.freeze({backPressure:"backPressure",backPressureEnd:"backPressureEnd",busy:"busy",busyEnd:"busyEnd",destroy:"destroy",empty:"empty",error:"error",full:"full",fullEnd:"fullEnd",ready:"ready",taskError:"taskError"}),l=1/1.5,c="default",m=Object.freeze(()=>{}),g=e=>Array.isArray(e)&&0!==e.length?1===e.length?e[0]:e.reduce((e,t)=>e+t,0)/e.length:0,y=e=>{if(!Array.isArray(e)||0===e.length)return 0;if(1===e.length)return e[0];const t=e.slice().sort((e,t)=>e-t);return(t[t.length-1>>1]+t[t.length>>1])/2},w=(e,t=2)=>{const r=10**t;return Math.round((e+Math.sign(e)*Number.EPSILON)*r)/r},p=e=>"object"==typeof e&&null!==e&&e.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),f=(e,t)=>t===e,N=e=>e?.constructor===(async()=>{}).constructor,T=()=>s.getRandomValues(new Uint32Array(1))[0]/4294967296,W=(...e)=>e.reduce((e,t)=>e<t?e:t,Number.POSITIVE_INFINITY),E=(...e)=>e.reduce((e,t)=>e>t?e:t,Number.NEGATIVE_INFINITY),S=(e,t)=>({name:e,...null!=t?.priority&&{priority:t.priority},...null!=t?.strategy&&{strategy:t.strategy},...null!=t?.workerNodeKeys&&{workerNodeKeys:t.workerNodeKeys}}),b=Object.freeze({FAIR_SHARE:"FAIR_SHARE",INTERLEAVED_WEIGHTED_ROUND_ROBIN:"INTERLEAVED_WEIGHTED_ROUND_ROBIN",LEAST_BUSY:"LEAST_BUSY",LEAST_ELU:"LEAST_ELU",LEAST_USED:"LEAST_USED",ROUND_ROBIN:"ROUND_ROBIN",WEIGHTED_ROUND_ROBIN:"WEIGHTED_ROUND_ROBIN"}),v=Object.freeze({elu:"elu",runTime:"runTime",waitTime:"waitTime"}),x=386,I=Object.freeze({cluster:"cluster",thread:"thread"}),F=Object.freeze({aggregate:!1,average:!1,median:!1}),O=e=>Object.freeze({agingFactor:.001,concurrency:1,loadExponent:l,size:e**2,tasksFinishedTimeout:2e3,tasksStealingOnBackPressure:!0,tasksStealingRatio:.6,taskStealing:!0}),P=e=>{if(null==e)throw new TypeError("The worker file path must be defined");if("string"!=typeof e)throw new TypeError("The worker file path must be a string");if(!t.existsSync(e))throw new Error(`Cannot find the worker file '${e}'`)},C=(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")},A=e=>{if(null!=e&&!Number.isSafeInteger(e))throw new TypeError(`Invalid property 'priority': '${e.toString()}'`);if(null!=e&&Number.isSafeInteger(e)&&(e<-20||e>19))throw new RangeError("Property 'priority' must be between -20 and 19")},z=e=>{if(null!=e&&!Object.values(b).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)},R=(e,t)=>{if(null!=e&&!Array.isArray(e))throw new TypeError("Invalid worker node keys: must be an array");if(0===e?.length)throw new RangeError("Invalid worker node keys: must not be an empty array");if(null!=e)for(const t of e)if(!Number.isSafeInteger(t)||t<0)throw new TypeError(`Invalid worker node key '${t.toString()}': must be a non-negative safe integer`);if(null!=e&&new Set(e).size!==e.length)throw new TypeError("Invalid worker node keys: must not contain duplicates");if(null!=t&&null!=e){if(e.length>t)throw new RangeError("Cannot add a task function with more worker node keys than the maximum number of workers in the pool");const r=e.filter(e=>e>=t);if(r.length>0)throw new RangeError(`Cannot add a task function with invalid worker node keys: ${r.toString()}. Valid keys are: 0..${(t-1).toString()}`)}},K=e=>{if(null!=e&&!p(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.toString()} 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.toString()} is a negative integer or zero`);if(null!=e?.agingFactor&&"number"!=typeof e.agingFactor)throw new TypeError("Invalid worker node tasks queue aging factor: must be a number");if(null!=e?.agingFactor&&e.agingFactor<0)throw new RangeError("Invalid worker node tasks queue aging factor: must be greater than or equal to 0");if(null!=e?.loadExponent&&"number"!=typeof e.loadExponent)throw new TypeError("Invalid worker node tasks queue load exponent: must be a number");if(null!=e?.loadExponent&&e.loadExponent<=0)throw new RangeError("Invalid worker node tasks queue load exponent: must be greater than 0");if(null!=e?.tasksStealingRatio&&"number"!=typeof e.tasksStealingRatio)throw new TypeError("Invalid worker node tasks stealing ratio: must be a number");if(null!=e?.tasksStealingRatio&&(e.tasksStealingRatio<0||e.tasksStealingRatio>1))throw new RangeError("Invalid worker node tasks stealing ratio: must be between 0 and 1")},q=(e,t,r)=>{null!=t&&null!=r&&t.aggregate&&(e.aggregate=(e.aggregate??0)+r,e.minimum=W(r,e.minimum??Number.POSITIVE_INFINITY),e.maximum=E(r,e.maximum??Number.NEGATIVE_INFINITY),(t.average||t.median)&&(e.history.put(r),t.average?e.average=g(e.history.toArray()):null!=e.average&&(e.average=void 0),t.median?e.median=y(e.history.toArray()):null!=e.median&&(e.median=void 0)))},M=(e,t,r)=>{const s=performance.now(),i=s-(r.timestamp??s);q(t.waitTime,e?.getTaskStatisticsRequirements().waitTime,i)},Q=(e,t)=>{const r=e.tasks;null!=r.executing&&r.executing>0&&--r.executing,null==t.workerError?++r.executed:++r.failed},D=(e,t,r)=>{null==r.workerError&&q(t.runTime,e?.getTaskStatisticsRequirements().runTime,r.taskPerformance?.runTime??0)},U=(e,t,r)=>{if(null!=r.workerError)return;const s=e?.getTaskStatisticsRequirements().elu;q(t.elu.active,s,r.taskPerformance?.elu?.active??0),q(t.elu.idle,s,r.taskPerformance?.elu?.idle??0),!0===s?.aggregate&&null!=r.taskPerformance?.elu&&(t.elu.count=(t.elu.count??0)+1,t.elu.utilization=((t.elu.utilization??0)*(t.elu.count-1)+r.taskPerformance.elu.utilization)/t.elu.count)},B=t=>t instanceof r.Worker?I.thread:t instanceof e.Worker?I.cluster:void 0,_=t=>t instanceof r.Worker?t.threadId:t instanceof e.Worker?t.id:void 0,L=Object.freeze({HARD:"HARD",SOFT:"SOFT"});class ${pool;opts;retriesCount;strategyPolicy=Object.freeze({dynamicWorkerReady:!0,dynamicWorkerUsage:!1});taskStatisticsRequirements=Object.freeze({elu:{...F},runTime:{...F},waitTime:{...F}});nextWorkerNodeKey;previousWorkerNodeKey;constructor(e,t){this.pool=e,this.opts=t,this.retriesCount=0,this.nextWorkerNodeKey=0,this.previousWorkerNodeKey=0,this.choose=this.choose.bind(this),this.setOptions(this.opts)}setOptions(e){this.opts=te(this.pool,e),this.setTaskStatisticsRequirements(this.opts)}checkWorkerNodeKey(e){if(!(null==e||e<0||e>=this.pool.workerNodes.length))return e}getRoundRobinNextWorkerNodeKey(){return this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:(this.nextWorkerNodeKey??this.previousWorkerNodeKey)+1}getSingleWorkerNodeKey(e){const[t]=e;return this.isWorkerNodeReady(t)?t:void 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}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}isWorkerNodeEligible(e,t){return this.isWorkerNodeReady(e)&&(null==t||t.has(e))}isWorkerNodeReady(e){return this.pool.workerNodes[e]?.info.ready??!1}resetWorkerNodeKeyProperties(){this.nextWorkerNodeKey=0,this.previousWorkerNodeKey=0}setPreviousWorkerNodeKey(e){this.previousWorkerNodeKey=null!=e&&e>=0&&e<this.pool.workerNodes.length?e:this.previousWorkerNodeKey}setTaskStatisticsRequirements(e){re(this.taskStatisticsRequirements.runTime,e.runTime.median),re(this.taskStatisticsRequirements.waitTime,e.waitTime.median),re(this.taskStatisticsRequirements.elu,e.elu.median)}}class V extends ${name=b.FAIR_SHARE;taskStatisticsRequirements=Object.freeze({elu:{aggregate:!0,average:!0,median:!1},runTime:{aggregate:!0,average:!0,median:!1},waitTime:{aggregate:!0,average:!0,median:!1}});constructor(e,t){super(e,t),this.setTaskStatisticsRequirements(this.opts)}choose(e){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.fairShareNextWorkerNodeKey(e),this.nextWorkerNodeKey}remove(e){return null!=this.pool.workerNodes[e]?.strategyData?.virtualTaskEndTimestamp&&(this.pool.workerNodes[e].strategyData.virtualTaskEndTimestamp=void 0),!0}reset(){for(const e of this.pool.workerNodes)null!=e.strategyData?.virtualTaskEndTimestamp&&(e.strategyData.virtualTaskEndTimestamp=void 0);return!0}update(e){return this.pool.workerNodes[e].strategyData={...this.pool.workerNodes[e].strategyData,virtualTaskEndTimestamp:this.computeWorkerNodeVirtualTaskEndTimestamp(e)},!0}computeWorkerNodeVirtualTaskEndTimestamp(e){return this.getWorkerNodeVirtualTaskEndTimestamp(e,this.getWorkerNodeVirtualTaskStartTimestamp(e))}fairShareNextWorkerNodeKey(e){if(0===e?.size)return;if(1===e?.size)return this.getSingleWorkerNodeKey(e);const t=this.pool.workerNodes.reduce((t,r,s,i)=>this.isWorkerNodeEligible(s,e)?(null==r.strategyData?.virtualTaskEndTimestamp&&(r.strategyData={...r.strategyData,virtualTaskEndTimestamp:this.computeWorkerNodeVirtualTaskEndTimestamp(s)}),-1===t||r.strategyData.virtualTaskEndTimestamp<i[t].strategyData.virtualTaskEndTimestamp?s:t):t,-1);return-1===t?void 0:t}getWorkerNodeVirtualTaskEndTimestamp(e,t){return t+(this.getWorkerNodeTaskWaitTime(e)+(this.opts?.measurement===v.elu?this.getWorkerNodeTaskElu(e):this.getWorkerNodeTaskRunTime(e)))}getWorkerNodeVirtualTaskStartTimestamp(e){const t=this.pool.workerNodes[e]?.strategyData?.virtualTaskEndTimestamp,r=performance.now();return r<(t??Number.NEGATIVE_INFINITY)?t:r}}class j extends ${name=b.INTERLEAVED_WEIGHTED_ROUND_ROBIN;taskStatisticsRequirements=Object.freeze({elu:{...F},runTime:{aggregate:!0,average:!0,median:!1},waitTime:{aggregate:!0,average:!0,median:!1}});roundId=0;roundWeights;workerNodeId=0;workerNodeVirtualTaskExecutionTime=0;constructor(e,t){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.roundWeights=this.getRoundWeights()}choose(e){if(0!==e?.size){if(1===e?.size)return this.getSingleWorkerNodeKey(e);for(let t=this.roundId;t<this.roundWeights.length;t++){this.roundId=t;for(let r=this.workerNodeId;r<this.pool.workerNodes.length;r++){this.workerNodeId=r,this.workerNodeId!==this.nextWorkerNodeKey&&0!==this.workerNodeVirtualTaskExecutionTime&&(this.workerNodeVirtualTaskExecutionTime=0);const s=this.opts.weights[r];if(this.isWorkerNodeEligible(r,e)&&s>=this.roundWeights[t]&&this.workerNodeVirtualTaskExecutionTime<s)return this.workerNodeVirtualTaskExecutionTime+=this.getWorkerNodeTaskWaitTime(r)+this.getWorkerNodeTaskRunTime(r),this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=r,this.nextWorkerNodeKey}}this.interleavedWeightedRoundRobinNextWorkerNodeId()}}remove(e){return 0===this.pool.workerNodes.length?(this.resetWorkerNodeKeyProperties(),this.workerNodeId=0,this.workerNodeVirtualTaskExecutionTime=0,!0):(null!=this.nextWorkerNodeKey&&this.nextWorkerNodeKey>=e&&(this.nextWorkerNodeKey=(this.nextWorkerNodeKey-1+this.pool.workerNodes.length)%this.pool.workerNodes.length),this.workerNodeId>=e&&(this.workerNodeId=(this.workerNodeId-1+this.pool.workerNodes.length)%this.pool.workerNodes.length),!0)}reset(){return this.resetWorkerNodeKeyProperties(),this.roundId=0,this.workerNodeId=0,this.workerNodeVirtualTaskExecutionTime=0,!0}setOptions(e){super.setOptions(e),this.roundWeights=this.getRoundWeights()}update(){return!0}getRoundWeights(){return[...new Set(Object.values(this.opts.weights).slice().sort((e,t)=>e-t))]}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}}class H extends ${name=b.LEAST_BUSY;taskStatisticsRequirements=Object.freeze({elu:{...F},runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1}});constructor(e,t){super(e,t),this.setTaskStatisticsRequirements(this.opts)}choose(e){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastBusyNextWorkerNodeKey(e),this.nextWorkerNodeKey}remove(){return!0}reset(){return!0}update(){return!0}leastBusyNextWorkerNodeKey(e){if(0===e?.size)return;if(1===e?.size)return this.getSingleWorkerNodeKey(e);const t=this.pool.workerNodes.reduce((t,r,s,i)=>this.isWorkerNodeEligible(s,e)&&(-1===t||(r.usage.waitTime.aggregate??0)+(r.usage.runTime.aggregate??0)<(i[t].usage.waitTime.aggregate??0)+(i[t].usage.runTime.aggregate??0))?s:t,-1);return-1===t?void 0:t}}class Y extends ${name=b.LEAST_ELU;taskStatisticsRequirements=Object.freeze({elu:{aggregate:!0,average:!1,median:!1},runTime:{...F},waitTime:{aggregate:!0,average:!1,median:!1}});constructor(e,t){super(e,t),this.setTaskStatisticsRequirements(this.opts)}choose(e){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastEluNextWorkerNodeKey(e),this.nextWorkerNodeKey}remove(){return!0}reset(){return!0}update(){return!0}leastEluNextWorkerNodeKey(e){if(0===e?.size)return;if(1===e?.size)return this.getSingleWorkerNodeKey(e);const t=this.pool.workerNodes.reduce((t,r,s,i)=>this.isWorkerNodeEligible(s,e)&&(-1===t||(r.usage.waitTime.aggregate??0)+(r.usage.elu.active.aggregate??0)<(i[t].usage.waitTime.aggregate??0)+(i[t].usage.elu.active.aggregate??0))?s:t,-1);return-1===t?void 0:t}}class G extends ${name=b.LEAST_USED;constructor(e,t){super(e,t)}choose(e){return this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey),this.nextWorkerNodeKey=this.leastUsedNextWorkerNodeKey(e),this.nextWorkerNodeKey}remove(){return!0}reset(){return!0}update(){return!0}leastUsedNextWorkerNodeKey(e){if(0===e?.size)return;if(1===e?.size)return this.getSingleWorkerNodeKey(e);const t=this.pool.workerNodes.reduce((t,r,s,i)=>this.isWorkerNodeEligible(s,e)&&(-1===t||r.usage.tasks.executing+r.usage.tasks.queued<i[t].usage.tasks.executing+i[t].usage.tasks.queued)?s:t,-1);return-1===t?void 0:t}}class J extends ${name=b.ROUND_ROBIN;constructor(e,t){super(e,t)}choose(e){this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey);const t=this.roundRobinNextWorkerNodeKey(e);if(null!=t&&this.isWorkerNodeEligible(t,e))return this.checkWorkerNodeKey(t)}remove(e){return 0===this.pool.workerNodes.length?this.reset():(null!=this.nextWorkerNodeKey&&this.nextWorkerNodeKey>=e&&(this.nextWorkerNodeKey=(this.nextWorkerNodeKey-1+this.pool.workerNodes.length)%this.pool.workerNodes.length,this.previousWorkerNodeKey>=e&&(this.previousWorkerNodeKey=this.nextWorkerNodeKey)),!0)}reset(){return this.resetWorkerNodeKeyProperties(),!0}update(){return!0}roundRobinNextWorkerNodeKey(e){if(null==e)return this.nextWorkerNodeKey=this.getRoundRobinNextWorkerNodeKey(),this.nextWorkerNodeKey;if(0===e.size)return;if(1===e.size){const t=this.getSingleWorkerNodeKey(e);return null!=t&&(this.nextWorkerNodeKey=t),t}const t=this.pool.workerNodes.length;for(let r=0;r<t;r++)if(this.nextWorkerNodeKey=this.getRoundRobinNextWorkerNodeKey(),e.has(this.nextWorkerNodeKey))return this.nextWorkerNodeKey}}class X extends ${name=b.WEIGHTED_ROUND_ROBIN;taskStatisticsRequirements=Object.freeze({elu:{...F},runTime:{aggregate:!0,average:!0,median:!1},waitTime:{aggregate:!0,average:!0,median:!1}});workerNodeVirtualTaskExecutionTime=0;constructor(e,t){super(e,t),this.setTaskStatisticsRequirements(this.opts)}choose(e){this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey);const t=this.weightedRoundRobinNextWorkerNodeKey(e);if(null!=t&&this.isWorkerNodeEligible(t,e))return this.checkWorkerNodeKey(t)}remove(e){return 0===this.pool.workerNodes.length?this.reset():(this.nextWorkerNodeKey===e&&(this.workerNodeVirtualTaskExecutionTime=0),null!=this.nextWorkerNodeKey&&this.nextWorkerNodeKey>=e&&(this.nextWorkerNodeKey=(this.nextWorkerNodeKey-1+this.pool.workerNodes.length)%this.pool.workerNodes.length,this.previousWorkerNodeKey>=e&&(this.previousWorkerNodeKey=this.nextWorkerNodeKey)),!0)}reset(){return this.resetWorkerNodeKeyProperties(),this.workerNodeVirtualTaskExecutionTime=0,!0}update(){return!0}findEligibleWorkerNodeKey(e){const t=this.pool.workerNodes.length;for(let r=0;r<t;r++)if(this.nextWorkerNodeKey=this.getRoundRobinNextWorkerNodeKey(),e.has(this.nextWorkerNodeKey))return this.nextWorkerNodeKey}weightedRoundRobinNextWorkerNodeKey(e){if(null==e){const e=this.nextWorkerNodeKey??this.previousWorkerNodeKey,t=this.opts.weights[e];return this.workerNodeVirtualTaskExecutionTime<t?(this.nextWorkerNodeKey=e,this.workerNodeVirtualTaskExecutionTime+=this.getWorkerNodeTaskWaitTime(e)+this.getWorkerNodeTaskRunTime(e)):(this.nextWorkerNodeKey=this.getRoundRobinNextWorkerNodeKey(),this.workerNodeVirtualTaskExecutionTime=0),this.nextWorkerNodeKey}if(0===e.size)return;if(1===e.size){const t=this.getSingleWorkerNodeKey(e);return null!=t&&(this.nextWorkerNodeKey=t,this.workerNodeVirtualTaskExecutionTime=0),t}const t=this.nextWorkerNodeKey??this.previousWorkerNodeKey;if(!e.has(t))return this.nextWorkerNodeKey=this.findEligibleWorkerNodeKey(e),this.workerNodeVirtualTaskExecutionTime=0,this.nextWorkerNodeKey;const r=this.opts.weights[t];return this.workerNodeVirtualTaskExecutionTime<r?(this.nextWorkerNodeKey=t,this.workerNodeVirtualTaskExecutionTime+=this.getWorkerNodeTaskWaitTime(t)+this.getWorkerNodeTaskRunTime(t)):(this.nextWorkerNodeKey=this.findEligibleWorkerNodeKey(e),this.workerNodeVirtualTaskExecutionTime=0),this.nextWorkerNodeKey}}const Z=()=>{const e=i.cpus();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/10**i)*10**i}return Math.round(r/e.length)},ee=(e,t)=>{t=t??Z();const r={};for(let s=0;s<e;s++)r[s]=t;return r},te=(e,t)=>((t=structuredClone(t??{})).weights=t.weights??ee(e.info.maxSize),{elu:{median:!1},runTime:{median:!1},waitTime:{median:!1},...t}),re=(e,t)=>{e.average&&t&&(e.average=!1,e.median=t),e.median&&!t&&(e.average=!0,e.median=t)},se=e=>{const t=Array.from(e,([e,t])=>t.strategyPolicy);return{dynamicWorkerReady:t.some(e=>e.dynamicWorkerReady),dynamicWorkerUsage:t.some(e=>e.dynamicWorkerUsage)}},ie=e=>{const t=Array.from(e,([e,t])=>t.taskStatisticsRequirements);return{elu:{aggregate:t.some(e=>e.elu.aggregate),average:t.some(e=>e.elu.average),median:t.some(e=>e.elu.median)},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)}}};class oe{pool;defaultWorkerChoiceStrategy;retries;workerChoiceStrategies;workerChoiceStrategiesPolicy;workerChoiceStrategiesTaskStatisticsRequirements;constructor(e,t=[b.LEAST_USED],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=se(this.workerChoiceStrategies),this.workerChoiceStrategiesTaskStatisticsRequirements=ie(this.workerChoiceStrategies),this.retries=((e,t)=>e.info.maxSize+Object.keys(t?.weights??ee(e.info.maxSize)).length)(this.pool,r)}execute(e=this.defaultWorkerChoiceStrategy,t){return this.executeStrategy(this.workerChoiceStrategies.get(e),t)}getPolicy(){return this.workerChoiceStrategiesPolicy}getStrategyRetries(){return Array.from(this.workerChoiceStrategies,([e,t])=>t.retriesCount).reduce((e,t)=>e+t,0)}getTaskStatisticsRequirements(){return this.workerChoiceStrategiesTaskStatisticsRequirements}remove(e){return Array.from(this.workerChoiceStrategies,([t,r])=>r.remove(e)).every(e=>e)}setDefaultWorkerChoiceStrategy(e,t){e!==this.defaultWorkerChoiceStrategy&&(this.defaultWorkerChoiceStrategy=e,this.addWorkerChoiceStrategy(e,this.pool,t))}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=se(this.workerChoiceStrategies),this.workerChoiceStrategiesTaskStatisticsRequirements=ie(this.workerChoiceStrategies)}update(e){return Array.from(this.workerChoiceStrategies,([t,r])=>r.update(e)).every(e=>e)}addWorkerChoiceStrategy(e,t,r){return this.workerChoiceStrategies.has(e)?this.workerChoiceStrategies:this.workerChoiceStrategies.set(e,((e,t,r,s)=>{switch(e){case b.FAIR_SHARE:return new(V.bind(r))(t,s);case b.INTERLEAVED_WEIGHTED_ROUND_ROBIN:return new(j.bind(r))(t,s);case b.LEAST_BUSY:return new(H.bind(r))(t,s);case b.LEAST_ELU:return new(Y.bind(r))(t,s);case b.LEAST_USED:return new(G.bind(r))(t,s);case b.ROUND_ROBIN:return new(J.bind(r))(t,s);case b.WEIGHTED_ROUND_ROBIN:return new(X.bind(r))(t,s);default:throw new Error(`Worker choice strategy '${e}' is not valid`)}})(e,t,this,r))}executeStrategy(e,t){let r=e.choose(t),s=0;for(;null==r&&s<this.retries;)s++,r=e.choose(t);if(e.retriesCount=s,null==r)throw new Error(`Worker node key chosen by ${e.name} is null or undefined after ${e.retriesCount.toString()} retries (max: ${this.retries.toString()})`);return r}removeWorkerChoiceStrategy(e){return this.workerChoiceStrategies.delete(e)}}class ne{size;items;maxArrayIdx;readIdx;writeIdx;constructor(e=2048){this.checkSize(e),this.readIdx=0,this.writeIdx=0,this.maxArrayIdx=e-1,this.size=0,this.items=new Float32Array(e)}clear(){this.readIdx=0,this.writeIdx=0,this.size=0}empty(){return 0===this.size}full(){return this.size===this.items.length}get(){if(this.empty())return;const e=this.items[this.readIdx];return this.readIdx=this.readIdx===this.maxArrayIdx?0:this.readIdx+1,--this.size,e}put(e){this.full()?this.readIdx=this.readIdx===this.maxArrayIdx?0:this.readIdx+1:++this.size,this.items[this.writeIdx]=e,this.writeIdx=this.writeIdx===this.maxArrayIdx?0:this.writeIdx+1}toArray(){if(this.empty())return[];const e=this.size,t=new Array(e);let r=this.readIdx;for(let s=0;s<e;s++)t[s]=this.items[r],r=r===this.maxArrayIdx?0:r+1;return t}checkSize(e){if(!Number.isSafeInteger(e))throw new TypeError(`Invalid circular buffer size: '${e.toString()}' is not an integer`);if(e<=0)throw new RangeError(`Invalid circular buffer size: ${e.toString()} <= 0`)}}class ae{capacity;nodeArray;size;start;constructor(e=2048){this.checkSize(e),this.capacity=e,this.nodeArray=new Array(this.capacity),this.clear()}clear(){if(this.size>0){let e=this.start;for(let t=0;t<this.size;t++)this.nodeArray[e]=void 0,++e,e===this.capacity&&(e=0)}this.start=0,this.size=0}delete(e){if(this.empty())return!1;let t=this.start,r=-1;for(let s=0;s<this.size;s++){if(this.nodeArray[t]?.data===e){r=s;break}++t,t===this.capacity&&(t=0)}if(-1!==r){if(r===this.size-1)return this.nodeArray[t]=void 0,--this.size,!0;let e=t;for(let t=r;t<this.size-1;t++){let t=e+1;t===this.capacity&&(t=0),this.nodeArray[e]=this.nodeArray[t],e=t}return this.nodeArray[e]=void 0,--this.size,!0}return!1}dequeue(){if(this.empty())return;const e=this.start,t=this.nodeArray[e].data;return this.nodeArray[e]=void 0,++this.start,this.start===this.capacity&&(this.start=0),--this.size,t}empty(){return 0===this.size}full(){return this.size===this.capacity}get(e){if(!(this.empty()||e<0||e>=this.size))return(e+=this.start)>=this.capacity&&(e-=this.capacity),this.nodeArray[e].data}[Symbol.iterator](){let e=this.start,t=0;return{next:()=>{if(t>=this.size)return{done:!0,value:void 0};const r=this.nodeArray[e].data;return++e,++t,e===this.capacity&&(e=0),{done:!1,value:r}}}}checkSize(e){if(!Number.isSafeInteger(e))throw new TypeError(`Invalid fixed queue size: '${e.toString()}' is not an integer`);if(e<=0)throw new RangeError(`Invalid fixed queue size: ${e.toString()} <= 0`)}}class ue extends ae{agingFactor;loadExponent;constructor(e,t=.001,r=1/1.5){super(e),this.agingFactor=t,this.loadExponent=r}enqueue(e,t){if(this.full())throw new Error("Fixed priority queue is full");t=t??0;const r=performance.now(),s=this.agingFactor*(1+((this.size+1)/this.capacity)**this.loadExponent);let i=-1,o=this.start;for(let e=0;e<this.size;e++){const e=this.nodeArray[o];if(e.priority-(r-e.timestamp)*s>t){i=o;break}++o,o===this.capacity&&(o=0)}let n=this.start+this.size;if(n>=this.capacity&&(n-=this.capacity),-1===i)i=n;else{let e=n;for(;e!==i;){const t=0===e?this.capacity-1:e-1;this.nodeArray[e]=this.nodeArray[t],e=t}}return this.nodeArray[i]={data:e,priority:t,timestamp:r},++this.size}}class he extends ae{enqueue(e,t){if(this.full())throw new Error("Fixed queue is full");let r=this.start+this.size;return r>=this.capacity&&(r-=this.capacity),this.nodeArray[r]={data:e,priority:t??0,timestamp:performance.now()},++this.size}}class ke{maxSize;size;get buckets(){return Math.trunc(this.size/this.bucketSize)}get enablePriority(){return this.priorityEnabled}set enablePriority(e){if(this.priorityEnabled===e)return;this.priorityEnabled=e;const t=Array.from(this);this.clear();for(const e of t)this.enqueue(e)}agingFactor;bucketSize;head;loadExponent;priorityEnabled;tail;constructor(e=2048,t=!1,r,s){if(!Number.isSafeInteger(e))throw new TypeError(`Invalid bucket size: '${e.toString()}' is not an integer`);if(e<=0)throw new RangeError(`Invalid bucket size: ${e.toString()} <= 0`);this.bucketSize=e,this.priorityEnabled=t,this.agingFactor=r??.001,this.loadExponent=s??l,this.clear()}clear(){this.head=this.tail=this.getPriorityQueueNode(),this.size=0,this.maxSize=0}delete(e){if(0===this.size)return!1;let t,r=this.tail;for(;null!=r;){if(r.delete(e))return r.empty()&&this.removePriorityQueueNode(r,t),--this.size,!0;t=r,r=r.next}return!1}dequeue(e){if(0===this.size)return;let t,r=this.tail;if(null!=e&&e>0){let s=1;for(;null!=r.next&&s<e;)t=r,r=r.next,++s;if(s<e||r.empty())return}else for(;!0===r?.empty()&&r!==this.head;)t=r,r=r.next;if(null==r||r.empty())return;const s=r.dequeue();return--this.size,r.empty()&&this.removePriorityQueueNode(r,t),s}enqueue(e,t){return this.head.full()&&(this.head=this.head.next=this.getPriorityQueueNode()),this.head.enqueue(e,t),++this.size,this.size>this.maxSize&&(this.maxSize=this.size),this.size}[Symbol.iterator](){let e=this.tail,t=0;return{next:()=>{for(;;){if(null==e)return{done:!0,value:void 0};for(;t>=e.size;)if(e=e.next,t=0,null==e)return{done:!0,value:void 0};const r=e.get(t);if(++t,null!=r)return{done:!1,value:r}}}}}getPriorityQueueNode(){let e;return e=this.priorityEnabled?new ue(this.bucketSize,this.agingFactor,this.loadExponent):new he(this.bucketSize),e}removePriorityQueueNode(e,t){this.head!==this.tail&&(e===this.tail&&null!=e.next?this.tail=e.next:e===this.head&&null!=t?(this.head=t,this.head.next=void 0):null!=t&&(t.next=e.next),e.next=void 0)}}class de extends n.EventEmitter{info;messageChannel;strategyData;tasksQueue;tasksQueueBackPressureSize;usage;worker;taskFunctionsUsage;constructor(t,s,i){var o;super(),((e,t,r)=>{if(null==e)throw new TypeError("Cannot construct a worker node without a worker type");if(!Object.values(I).includes(e))throw new TypeError(`Cannot construct a worker node with an invalid worker type '${e}'`);if(P(t),null==r)throw new TypeError("Cannot construct a worker node without worker node options");if(!p(r))throw new TypeError("Cannot construct a worker node with invalid worker node 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");if(null==r.tasksQueuePriority)throw new TypeError("Cannot construct a worker node without a tasks queue priority option");if("boolean"!=typeof r.tasksQueuePriority)throw new TypeError("Cannot construct a worker node with a tasks queue priority option that is not a boolean")})(t,s,i),this.worker=((t,s,i)=>{switch(t){case I.cluster:return e.fork(i.env);case I.thread:return new r.Worker(s,{env:r.SHARE_ENV,...i.workerOptions});default:throw new Error(`Unknown worker type '${t}'`)}})(t,s,{env:i.env,workerOptions:i.workerOptions}),this.info=(o=this.worker,{backPressure:!1,backPressureStealing:!1,continuousStealing:!1,dynamic:!1,id:_(o),queuedTaskAbortion:!1,ready:!1,stealing:!1,stolen:!1,type:B(o)}),this.usage=this.initWorkerUsage(),this.info.type===I.thread&&(this.messageChannel=new r.MessageChannel),this.tasksQueueBackPressureSize=i.tasksQueueBackPressureSize,this.tasksQueue=new ke(i.tasksQueueBucketSize,i.tasksQueuePriority,i.tasksQueueAgingFactor,i.tasksQueueLoadExponent),this.taskFunctionsUsage=new Map}clearTasksQueue(){this.tasksQueue.clear()}deleteTask(e){return this.tasksQueue.delete(e)}deleteTaskFunctionWorkerUsage(e){return this.taskFunctionsUsage.delete(e)}dequeueLastPrioritizedTask(){return this.dequeueTask(this.tasksQueue.buckets+1)}dequeueTask(e){const t=this.tasksQueue.dequeue(e);return!this.hasBackPressure()&&this.info.backPressure&&(this.info.backPressure=!1),t}enqueueTask(e){const t=this.tasksQueue.enqueue(e,e.priority);return this.hasBackPressure()&&!this.info.backPressure&&(this.info.backPressure=!0,this.emit("backPressure",{workerId:this.info.id})),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===c&&(e=this.info.taskFunctionsProperties[1].name),this.taskFunctionsUsage.has(e)||this.taskFunctionsUsage.set(e,this.initTaskFunctionWorkerUsage(e)),this.taskFunctionsUsage.get(e)}registerOnceWorkerEventHandler(e,t){this.worker.once(e,t)}registerWorkerEventHandler(e,t){this.worker.on(e,t)}setTasksQueuePriority(e){this.tasksQueue.enablePriority=e}tasksQueueSize(){return this.tasksQueue.size}async terminate(){const e=new Promise(e=>{this.registerOnceWorkerEventHandler("exit",()=>{e()})});switch(this.closeMessageChannel(),this.removeAllListeners(),this.info.type){case I.cluster:this.registerOnceWorkerEventHandler("disconnect",()=>{this.worker.kill?.()}),this.worker.disconnect?.();break;case I.thread:this.worker.unref?.(),await(this.worker.terminate?.())}await e,this.worker.removeAllListeners()}closeMessageChannel(){null!=this.messageChannel&&(this.messageChannel.port1.unref(),this.messageChannel.port2.unref(),this.messageChannel.port1.close(),this.messageChannel.port2.close(),delete this.messageChannel)}hasBackPressure(){return this.tasksQueue.size>=this.tasksQueueBackPressureSize}initTaskFunctionWorkerUsage(e){const t=()=>{let t=0;for(const r of this.tasksQueue)(r.name===c&&e===this.info.taskFunctionsProperties[1].name||r.name!==c&&e===r.name)&&++t;return t};return{elu:{active:{history:new ne(x)},idle:{history:new ne(x)}},runTime:{history:new ne(x)},tasks:{executed:0,executing:0,failed:0,get queued(){return t()},sequentiallyStolen:0,stolen:0},waitTime:{history:new ne(x)}}}initWorkerUsage(){const e=()=>this.tasksQueue.size,t=()=>this.tasksQueue.maxSize;return{elu:{active:{history:new ne(x)},idle:{history:new ne(x)}},runTime:{history:new ne(x)},tasks:{executed:0,executing:0,failed:0,get maxQueued(){return t()},get queued(){return e()},sequentiallyStolen:0,stolen:0},waitTime:{history:new ne(x)}}}}class le{minimumNumberOfWorkers;filePath;opts;maximumNumberOfWorkers;emitter;workerNodes=[];get info(){const e=this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements();return{defaultStrategy:this.opts.workerChoiceStrategy,maxSize:this.maximumNumberOfWorkers??this.minimumNumberOfWorkers,minSize:this.minimumNumberOfWorkers,ready:this.ready,started:this.started,strategyRetries:this.workerChoiceStrategiesContext?.getStrategyRetries()??0,type:this.type,version:"5.3.2",worker:this.worker,...!0===e?.runTime.aggregate&&e.waitTime.aggregate&&{utilization:w(this.utilization)},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),failedTasks:this.workerNodes.reduce((e,t)=>e+t.usage.tasks.failed,0),idleWorkerNodes:this.workerNodes.reduce((e,t,r)=>this.isWorkerNodeIdle(r)?e+1:e,0),workerNodes:this.workerNodes.length,...this.type===k.dynamic&&{dynamicWorkerNodes:this.workerNodes.reduce((e,t)=>t.info.dynamic?e+1:e,0)},...!0===this.opts.enableTasksQueue&&{backPressure:this.backPressure,backPressureWorkerNodes:this.workerNodes.reduce((e,t,r)=>this.isWorkerNodeBackPressured(r)?e+1:e,0),maxQueuedTasks:this.workerNodes.reduce((e,t)=>e+(t.usage.tasks.maxQueued??0),0),queuedTasks:this.getQueuedTasks(),stealingWorkerNodes:this.getStealingWorkerNodes(),stolenTasks:this.workerNodes.reduce((e,t)=>e+t.usage.tasks.stolen,0)},...!0===e?.runTime.aggregate&&{runTime:{maximum:w(E(...this.workerNodes.map(e=>e.usage.runTime.maximum??Number.NEGATIVE_INFINITY))),minimum:w(W(...this.workerNodes.map(e=>e.usage.runTime.minimum??Number.POSITIVE_INFINITY))),...e.runTime.average&&{average:w(g(this.workerNodes.reduce((e,t)=>e.concat(t.usage.runTime.history.toArray()),[])))},...e.runTime.median&&{median:w(y(this.workerNodes.reduce((e,t)=>e.concat(t.usage.runTime.history.toArray()),[])))}}},...!0===e?.waitTime.aggregate&&{waitTime:{maximum:w(E(...this.workerNodes.map(e=>e.usage.waitTime.maximum??Number.NEGATIVE_INFINITY))),minimum:w(W(...this.workerNodes.map(e=>e.usage.waitTime.minimum??Number.POSITIVE_INFINITY))),...e.waitTime.average&&{average:w(g(this.workerNodes.reduce((e,t)=>e.concat(t.usage.waitTime.history.toArray()),[])))},...e.waitTime.median&&{median:w(y(this.workerNodes.reduce((e,t)=>e.concat(t.usage.waitTime.history.toArray()),[])))}}},...!0===e?.elu.aggregate&&{elu:{active:{maximum:w(E(...this.workerNodes.map(e=>e.usage.elu.active.maximum??Number.NEGATIVE_INFINITY))),minimum:w(W(...this.workerNodes.map(e=>e.usage.elu.active.minimum??Number.POSITIVE_INFINITY))),...e.elu.average&&{average:w(g(this.workerNodes.reduce((e,t)=>e.concat(t.usage.elu.active.history.toArray()),[])))},...e.elu.median&&{median:w(y(this.workerNodes.reduce((e,t)=>e.concat(t.usage.elu.active.history.toArray()),[])))}},idle:{maximum:w(E(...this.workerNodes.map(e=>e.usage.elu.idle.maximum??Number.NEGATIVE_INFINITY))),minimum:w(W(...this.workerNodes.map(e=>e.usage.elu.idle.minimum??Number.POSITIVE_INFINITY))),...e.elu.average&&{average:w(g(this.workerNodes.reduce((e,t)=>e.concat(t.usage.elu.idle.history.toArray()),[])))},...e.elu.median&&{median:w(y(this.workerNodes.reduce((e,t)=>e.concat(t.usage.elu.idle.history.toArray()),[])))}},utilization:{average:w(g(this.workerNodes.map(e=>e.usage.elu.utilization??0))),median:w(y(this.workerNodes.map(e=>e.usage.elu.utilization??0)))}}}}}destroying;promiseResponseMap=new Map;started;starting;workerChoiceStrategiesContext;backPressureEventEmitted;busyEventEmitted;readyEventEmitted;startingMinimumNumberOfWorkers;startTimestamp;taskFunctions;get ready(){return!!this.started&&this.workerNodes.reduce((e,t)=>!t.info.dynamic&&t.info.ready?e+1:e,0)>=this.minimumNumberOfWorkers}get utilization(){if(null==this.startTimestamp)return 0;const e=(a.performance.now()-this.startTimestamp)*(this.maximumNumberOfWorkers??this.minimumNumberOfWorkers);if(!Number.isFinite(e)||e<=0)return 0;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}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(),P(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 oe(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.busyEventEmitted=!1,this.backPressureEventEmitted=!1,this.startingMinimumNumberOfWorkers=!1,!0===this.opts.startWorkers&&this.start()}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");A(t.priority),z(t.strategy),R(t.workerNodeKeys,this.maximumNumberOfWorkers??this.minimumNumberOfWorkers);const r=await this.sendTaskFunctionOperationToWorkers({taskFunction:t.taskFunction.toString(),taskFunctionOperation:"add",taskFunctionProperties:S(e,t)});this.taskFunctions.set(e,t),this.workerChoiceStrategiesContext?.syncWorkerChoiceStrategies(this.getWorkerChoiceStrategies());for(const e of this.workerNodes.keys())this.sendStatisticsMessageToWorker(e);return r}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;try{await Promise.allSettled(this.workerNodes.map(async(e,t)=>{try{await this.destroyWorkerNode(t)}catch(e){this.emitter?.emit(d.error,e)}}))}finally{delete this.startTimestamp,this.destroying=!1,this.started=!1,null!=this.emitter&&(this.emitter.listenerCount(d.destroy)>0&&this.emitter.emit(d.destroy,this.info),this.emitter.emitDestroy(),this.readyEventEmitted=!1)}}enableTasksQueue(e,t){!0!==this.opts.enableTasksQueue||e||(this.unsetTaskStealing(),this.unsetTasksStealingOnBackPressure(),this.flushTasksQueues()),this.opts.enableTasksQueue=e,this.setTasksQueueOptions(t)}async execute(e,t,r,s){if(!this.started)throw new Error("Cannot execute a task on not started pool");if(this.destroying)throw new Error("Cannot execute a task on destroying pool");if(null!=t&&"string"!=typeof t)throw new TypeError("name argument must be a string");if(null!=t&&"string"==typeof t&&0===t.trim().length)throw new TypeError("name argument must not be an empty string");if(null!=r&&!(r instanceof AbortSignal))throw new TypeError("abortSignal argument must be an AbortSignal");if(null!=s&&!Array.isArray(s))throw new TypeError("transferList argument must be an array");return await this.internalExecute(e,t,r,s)}hasTaskFunction(e){return this.listTaskFunctionsProperties().some(t=>t.name===e)}listTaskFunctionsProperties(){for(const e of this.workerNodes)if(Array.isArray(e.info.taskFunctionsProperties)&&e.info.taskFunctionsProperties.length>0)return e.info.taskFunctionsProperties;return[]}async mapExecute(e,t,r,s){if(!this.started)throw new Error("Cannot execute task(s) on not started pool");if(this.destroying)throw new Error("Cannot execute task(s) on destroying pool");if(null==e)throw new TypeError("data argument must be a defined iterable");if("function"!=typeof e[Symbol.iterator])throw new TypeError("data argument must be an iterable");if(null!=t&&"string"!=typeof t)throw new TypeError("name argument must be a string");if(null!=t&&"string"==typeof t&&0===t.trim().length)throw new TypeError("name argument must not be an empty string");if(Array.isArray(e)||(e=[...e]),null!=r){if("function"!=typeof r[Symbol.iterator])throw new TypeError("abortSignals argument must be an iterable");for(const e of r)if(!(e instanceof AbortSignal))throw new TypeError("abortSignals argument must be an iterable of AbortSignal");if(Array.isArray(r)||(r=[...r]),e.length!==r.length)throw new Error("data and abortSignals arguments must have the same length")}if(null!=s&&!Array.isArray(s))throw new TypeError("transferList argument must be an array");const i=Array.from({length:e.length},(t,s)=>[e[s],null!=r?r[s]:void 0]);return await Promise.all(i.map(([e,r])=>this.internalExecute(e,t,r,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:S(e,this.taskFunctions.get(e))});for(const t of this.workerNodes)t.deleteTaskFunctionWorkerUsage(e);this.taskFunctions.delete(e),this.workerChoiceStrategiesContext?.syncWorkerChoiceStrategies(this.getWorkerChoiceStrategies());for(const e of this.workerNodes.keys())this.sendStatisticsMessageToWorker(e);return t}async setDefaultTaskFunction(e){return await this.sendTaskFunctionOperationToWorkers({taskFunctionOperation:"default",taskFunctionProperties:S(e,this.taskFunctions.get(e))})}setTasksQueueOptions(e){!0===this.opts.enableTasksQueue?(K(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}setWorkerChoiceStrategy(e,t){let r=!1;if(z(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.getWorkerChoiceStrategies(),this.opts.workerChoiceStrategyOptions);for(const e of this.workerNodes.keys())this.sendStatisticsMessageToWorker(e)}}setWorkerChoiceStrategyOptions(e){if(this.checkValidWorkerChoiceStrategyOptions(e),null!=e){this.opts.workerChoiceStrategyOptions={...this.opts.workerChoiceStrategyOptions,...e},this.workerChoiceStrategiesContext?.setOptions(this.opts.workerChoiceStrategyOptions),this.workerChoiceStrategiesContext?.syncWorkerChoiceStrategies(this.getWorkerChoiceStrategies(),this.opts.workerChoiceStrategyOptions);for(const e of this.workerNodes.keys())this.sendStatisticsMessageToWorker(e);return!0}return!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=a.performance.now(),this.starting=!1,this.started=!0}afterTaskExecutionHook(e,t){let r=!1;if(null!=this.workerNodes[e]?.usage){const s=this.workerNodes[e].usage;Q(s,t),D(this.workerChoiceStrategiesContext,s,t),U(this.workerChoiceStrategiesContext,s,t),r=!0}if(this.shallUpdateTaskFunctionWorkerUsage(e)&&null!=t.taskPerformance?.name&&null!=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance.name)){const s=this.workerNodes[e].getTaskFunctionWorkerUsage(t.taskPerformance.name);Q(s,t),D(this.workerChoiceStrategiesContext,s,t),U(this.workerChoiceStrategiesContext,s,t),r=!0}r&&this.workerChoiceStrategiesContext?.update(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)),this.workerNodes[e].on("abortTask",this.abortTask)}beforeTaskExecutionHook(e,t){if(null!=this.workerNodes[e]?.usage){const r=this.workerNodes[e].usage;++r.tasks.executing,M(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,M(this.workerChoiceStrategiesContext,r,t)}}createAndSetupDynamicWorkerNode(){const e=this.createAndSetupWorkerNode();if(this.registerWorkerMessageListener(e,e=>{if(this.destroying)return;this.checkMessageWorkerId(e);const t=this.getWorkerNodeKeyByWorkerId(e.workerId);(f(L.HARD,e.kill)||f(L.SOFT,e.kill)&&this.isWorkerNodeIdle(t)&&!this.isWorkerNodeStealing(t))&&this.destroyWorkerNode(t).catch(e=>{this.emitter?.emit(d.error,e)})}),this.sendToWorker(e,{checkActive:!0}),this.taskFunctions.size>0)for(const[t,r]of this.taskFunctions)this.sendTaskFunctionOperationToWorker(e,{taskFunction:r.taskFunction.toString(),taskFunctionOperation:"add",taskFunctionProperties:S(t,r)}).catch(e=>{this.emitter?.emit(d.error,e)});const t=this.workerNodes[e];return t.info.dynamic=!0,!0===this.workerChoiceStrategiesContext?.getPolicy().dynamicWorkerReady&&(t.info.ready=!0),this.initWorkerNodeUsage(t),this.checkAndEmitDynamicWorkerCreationEvents(),e}createAndSetupWorkerNode(){const e=this.createWorkerNode();e.registerWorkerEventHandler("online",this.opts.onlineHandler??m),e.registerWorkerEventHandler("message",this.opts.messageHandler??m),e.registerWorkerEventHandler("error",this.opts.errorHandler??m),e.registerOnceWorkerEventHandler("error",t=>{e.info.ready=!1,this.emitter?.emit(d.error,t),this.started&&!this.destroying&&(!0===this.opts.restartWorkerOnError&&(e.info.dynamic?this.createAndSetupDynamicWorkerNode():this.startingMinimumNumberOfWorkers||this.startMinimumNumberOfWorkers(!0)),!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(this.workerNodes.indexOf(e))),e?.terminate().catch(e=>{this.emitter?.emit(d.error,e)})}),e.registerWorkerEventHandler("exit",this.opts.exitHandler??m),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}async destroyWorkerNode(e){this.flagWorkerNodeAsNotReady(e);const t=this.flushTasksQueue(e),r=this.workerNodes[e];await(async(e,t,r,s,i=!0)=>await new Promise((o,n)=>{let a=0;if(0===r)return void o(a);const u=()=>{++a,a>=r&&(null!=h&&clearTimeout(h),e.off(t,u),o(a))},h=s>=0?setTimeout(()=>{e.off(t,u),i?n(new Error(`Timed out after ${s.toString()}ms waiting for ${r.toString()} '${t}' events. Received ${a.toString()} events`)):o(a)},s):void 0;switch(t){case"backPressure":case"idle":case"taskFinished":e.on(t,u);break;default:null!=h&&clearTimeout(h),n(new Error("Invalid worker node event"))}}))(r,"taskFinished",t,this.opts.tasksQueueOptions?.tasksFinishedTimeout??O(this.maximumNumberOfWorkers??this.minimumNumberOfWorkers).tasksFinishedTimeout,!1),await this.sendKillMessageToWorker(e),await r.terminate()}flagWorkerNodeAsNotReady(e){const t=this.getWorkerInfo(e);null!=t&&(t.ready=!1)}flushTasksQueue(e){let t=0;for(;this.tasksQueueSize(e)>0;)this.executeTask(e,this.dequeueTask(e)),++t;return this.workerNodes[e].clearTasksQueue(),t}getWorkerInfo(e){return this.workerNodes[e]?.info}internalBackPressure(){return 0!==this.workerNodes.length&&this.workerNodes.reduce((e,t,r)=>this.isWorkerNodeBackPressured(r)?e+1:e,0)===this.workerNodes.length}internalBusy(){return 0!==this.workerNodes.length&&this.workerNodes.reduce((e,t,r)=>th