poolifier 2.6.24 → 2.6.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -8
- package/lib/index.js +1 -1
- package/lib/index.mjs +1 -1
- package/lib/pools/abstract-pool.d.ts +9 -2
- package/lib/pools/pool.d.ts +6 -0
- package/lib/pools/version.d.ts +1 -1
- package/lib/utility-types.d.ts +5 -1
- package/lib/worker/abstract-worker.d.ts +4 -0
- package/lib/worker/worker-options.d.ts +8 -0
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -110,7 +110,7 @@ const { DynamicThreadPool, FixedThreadPool, PoolEvents, availableParallelism } =
|
|
|
110
110
|
|
|
111
111
|
// a fixed worker_threads pool
|
|
112
112
|
const pool = new FixedThreadPool(availableParallelism(), './yourWorker.js', {
|
|
113
|
-
errorHandler: e => console.error(e),
|
|
113
|
+
errorHandler: (e) => console.error(e),
|
|
114
114
|
onlineHandler: () => console.info('worker is online')
|
|
115
115
|
})
|
|
116
116
|
|
|
@@ -119,7 +119,7 @@ pool.emitter.on(PoolEvents.busy, () => console.info('Pool is busy'))
|
|
|
119
119
|
|
|
120
120
|
// or a dynamic worker_threads pool
|
|
121
121
|
const pool = new DynamicThreadPool(Math.floor(availableParallelism() / 2), availableParallelism(), './yourWorker.js', {
|
|
122
|
-
errorHandler: e => console.error(e),
|
|
122
|
+
errorHandler: (e) => console.error(e),
|
|
123
123
|
onlineHandler: () => console.info('worker is online')
|
|
124
124
|
})
|
|
125
125
|
|
|
@@ -131,10 +131,10 @@ pool.emitter.on(PoolEvents.busy, () => console.info('Pool is busy'))
|
|
|
131
131
|
// so you can easy switch from one to another
|
|
132
132
|
pool
|
|
133
133
|
.execute()
|
|
134
|
-
.then(res => {
|
|
134
|
+
.then((res) => {
|
|
135
135
|
console.info(res)
|
|
136
136
|
})
|
|
137
|
-
.catch(err => {
|
|
137
|
+
.catch((err) => {
|
|
138
138
|
console.error(err)
|
|
139
139
|
})
|
|
140
140
|
```
|
|
@@ -146,11 +146,16 @@ You can do the same with the classes _ClusterWorker_, _FixedClusterPool_ and _Dy
|
|
|
146
146
|
- [Javascript](./examples/javascript/)
|
|
147
147
|
- [Typescript](./examples/typescript/)
|
|
148
148
|
- [HTTP client pool](./examples/typescript/http-client-pool/)
|
|
149
|
+
- [SMTP client pool](./examples/typescript/smtp-client-pool/)
|
|
149
150
|
- [HTTP server pool](./examples/typescript/http-server-pool/)
|
|
150
|
-
- [Express](./examples/typescript/http-server-pool/express/)
|
|
151
|
-
- [Fastify](./examples/typescript/http-server-pool/fastify/)
|
|
152
|
-
|
|
153
|
-
- [
|
|
151
|
+
- [Express worker_threads pool](./examples/typescript/http-server-pool/express-worker_threads/)
|
|
152
|
+
- [Fastify worker_threads pool](./examples/typescript/http-server-pool/fastify-worker_threads/)
|
|
153
|
+
- [Fastify cluster pool](./examples/typescript/http-server-pool/fastify-cluster/)
|
|
154
|
+
- [Fastify hybrid pool](./examples/typescript/http-server-pool/fastify-hybrid/)
|
|
155
|
+
- [WebSocket server pool](./examples/typescript/websocket-server-pool/)
|
|
156
|
+
- [ws worker_threads pool](./examples/typescript/websocket-server-pool/ws-worker_threads/)
|
|
157
|
+
- [ws cluster pool](./examples/typescript/websocket-server-pool/ws-cluster/)
|
|
158
|
+
- [ws hybrid pool](./examples/typescript/websocket-server-pool/ws-hybrid/)
|
|
154
159
|
|
|
155
160
|
Remember that workers can only send and receive structured-cloneable data.
|
|
156
161
|
|
package/lib/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("node:events"),t=require("node:worker_threads"),s=require("node:cluster"),r=require("node:crypto"),i=require("node:perf_hooks"),o=require("node:fs"),n=require("node:os"),a=require("node:async_hooks");function h(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(s){if("default"!==s){var r=Object.getOwnPropertyDescriptor(e,s);Object.defineProperty(t,s,r.get?r:{enumerable:!0,get:function(){return e[s]}})}})),t.default=e,Object.freeze(t)}var u=h(n);const k=Object.freeze({fixed:"fixed",dynamic:"dynamic"});class c extends e.EventEmitter{}const d=Object.freeze({full:"full",ready:"ready",busy:"busy",error:"error",taskError:"taskError"}),l="default",m=Object.freeze((()=>{})),g={runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},p={aggregate:!1,average:!1,median:!1},w=e=>{if(Array.isArray(e)&&0===e.length)return 0;if(Array.isArray(e)&&1===e.length)return e[0];const t=e.slice().sort(((e,t)=>e-t));return(t[t.length-1>>1]+t[t.length>>1])/2},y=(e,t=2)=>{const s=Math.pow(10,t);return Math.round(e*s*(1+Number.EPSILON))/s},f=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),T=(e,t,s,r)=>{t.aggregate&&(e.aggregate=(e.aggregate??0)+s,e.minimum=Math.min(s,e.minimum??1/0),e.maximum=Math.max(s,e.maximum??-1/0),t.average&&0!==r&&(e.average=e.aggregate/r),t.median&&null!=s&&(e.history.push(s),e.median=w(e.history)))},W=Object.freeze({SOFT:"SOFT",HARD:"HARD"}),N=Object.freeze({ROUND_ROBIN:"ROUND_ROBIN",LEAST_USED:"LEAST_USED",LEAST_BUSY:"LEAST_BUSY",LEAST_ELU:"LEAST_ELU",FAIR_SHARE:"FAIR_SHARE",WEIGHTED_ROUND_ROBIN:"WEIGHTED_ROUND_ROBIN",INTERLEAVED_WEIGHTED_ROUND_ROBIN:"INTERLEAVED_WEIGHTED_ROUND_ROBIN"}),x=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"});class S{pool;opts;nextWorkerNodeKey=0;strategyPolicy={useDynamicWorker:!1};taskStatisticsRequirements={runTime:p,waitTime:p,elu:p};constructor(e,t=g){this.pool=e,this.opts=t,this.choose=this.choose.bind(this)}setTaskStatisticsRequirements(e){this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.runTime,e.runTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.waitTime,e.waitTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.elu,e.elu?.median)}toggleMedianMeasurementStatisticsRequirements(e,t){e.average&&t&&(e.average=!1,e.median=t),e.median&&!t&&(e.average=!0,e.median=t)}setOptions(e){this.opts=e??g,this.setTaskStatisticsRequirements(this.opts)}isWorkerNodeReady(e){return this.pool.workerNodes[e].info.ready}getWorkerTaskRunTime(e){return this.taskStatisticsRequirements.runTime.median?this.pool.workerNodes[e].usage.runTime?.median??0:this.pool.workerNodes[e].usage.runTime?.average??0}getWorkerTaskWaitTime(e){return this.taskStatisticsRequirements.waitTime.median?this.pool.workerNodes[e].usage.waitTime?.median??0:this.pool.workerNodes[e].usage.waitTime?.average??0}getWorkerTaskElu(e){return this.taskStatisticsRequirements.elu.median?this.pool.workerNodes[e].usage.elu.active?.median??0:this.pool.workerNodes[e].usage.elu.active?.average??0}computeDefaultWorkerWeight(){let e=0;for(const t of n.cpus()){const s=t.speed.toString().length-1;e+=1/(t.speed/Math.pow(10,s))*Math.pow(10,s)}return Math.round(e/n.cpus().length)}}class E extends S{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:p,elu:{aggregate:!0,average:!0,median:!1}};workersVirtualTaskEndTimestamp=[];constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.workersVirtualTaskEndTimestamp=[],!0}update(e){return this.computeWorkerVirtualTaskEndTimestamp(e),!0}choose(){return this.fairShareNextWorkerNodeKey()}remove(e){return this.workersVirtualTaskEndTimestamp.splice(e,1),!0}fairShareNextWorkerNodeKey(){let e=1/0;for(const[t]of this.pool.workerNodes.entries()){null==this.workersVirtualTaskEndTimestamp[t]&&this.computeWorkerVirtualTaskEndTimestamp(t);const s=this.workersVirtualTaskEndTimestamp[t];this.isWorkerNodeReady(t)&&s<e&&(e=s,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}computeWorkerVirtualTaskEndTimestamp(e){this.workersVirtualTaskEndTimestamp[e]=this.getWorkerVirtualTaskEndTimestamp(e,this.getWorkerVirtualTaskStartTimestamp(e))}getWorkerVirtualTaskEndTimestamp(e,t){return t+(this.opts.measurement===x.elu?this.getWorkerTaskElu(e):this.getWorkerTaskRunTime(e))}getWorkerVirtualTaskStartTimestamp(e){return Math.max(performance.now(),this.workersVirtualTaskEndTimestamp[e]??-1/0)}}class I extends S{strategyPolicy={useDynamicWorker:!0};roundId=0;roundWeights;defaultWorkerWeight;constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight(),this.roundWeights=this.getRoundWeights()}reset(){return this.nextWorkerNodeKey=0,this.roundId=0,!0}update(){return!0}choose(){let e,t;for(let s=this.roundId;s<this.roundWeights.length;s++)for(let r=this.nextWorkerNodeKey;r<this.pool.workerNodes.length;r++){const i=this.opts.weights?.[r]??this.defaultWorkerWeight;if(this.isWorkerNodeReady(r)&&i>=this.roundWeights[s]){e=s,t=r;break}}this.roundId=e??0,this.nextWorkerNodeKey=t??0;const s=this.nextWorkerNodeKey;return this.nextWorkerNodeKey===this.pool.workerNodes.length-1?(this.nextWorkerNodeKey=0,this.roundId=this.roundId===this.roundWeights.length-1?0:this.roundId+1):this.nextWorkerNodeKey=this.nextWorkerNodeKey+1,s}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1,this.roundId=this.roundId===this.roundWeights.length-1?0:this.roundId+1)),!0}setOptions(e){super.setOptions(e),this.roundWeights=this.getRoundWeights()}getRoundWeights(){return null==this.opts.weights?[this.defaultWorkerWeight]:[...new Set(Object.values(this.opts.weights).slice().sort(((e,t)=>e-t)))]}}class b extends S{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:p};constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.leastBusyNextWorkerNodeKey()}remove(){return!0}leastBusyNextWorkerNodeKey(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=(s.usage.runTime?.aggregate??0)+(s.usage.waitTime?.aggregate??0);if(this.isWorkerNodeReady(t)&&0===r){this.nextWorkerNodeKey=t;break}this.isWorkerNodeReady(t)&&r<e&&(e=r,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}}class C extends S{constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.leastUsedNextWorkerNodeKey()}remove(){return!0}leastUsedNextWorkerNodeKey(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=s.usage.tasks,i=r.executed+r.executing+r.queued;if(this.isWorkerNodeReady(t)&&0===i){this.nextWorkerNodeKey=t;break}this.isWorkerNodeReady(t)&&i<e&&(e=i,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}}class R extends S{taskStatisticsRequirements={runTime:p,waitTime:p,elu:{aggregate:!0,average:!1,median:!1}};constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.leastEluNextWorkerNodeKey()}remove(){return!0}leastEluNextWorkerNodeKey(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=s.usage,i=r.elu?.active?.aggregate??0;if(this.isWorkerNodeReady(t)&&0===i){this.nextWorkerNodeKey=t;break}this.isWorkerNodeReady(t)&&i<e&&(e=i,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}}class v extends S{strategyPolicy={useDynamicWorker:!0};constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.nextWorkerNodeKey=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;do{this.roundRobinNextWorkerNodeKey()}while(!this.isWorkerNodeReady(this.nextWorkerNodeKey));return e}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1)),!0}roundRobinNextWorkerNodeKey(){return this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:this.nextWorkerNodeKey+1,this.nextWorkerNodeKey}}class O extends S{strategyPolicy={useDynamicWorker:!0};taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:p,elu:p};defaultWorkerWeight;workerVirtualTaskRunTime=0;constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight()}reset(){return this.nextWorkerNodeKey=0,this.workerVirtualTaskRunTime=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;do{this.weightedRoundRobinNextWorkerNodeKey()}while(!this.isWorkerNodeReady(this.nextWorkerNodeKey));return e}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1),this.workerVirtualTaskRunTime=0),!0}weightedRoundRobinNextWorkerNodeKey(){const e=this.workerVirtualTaskRunTime;return e<(this.opts.weights?.[this.nextWorkerNodeKey]??this.defaultWorkerWeight)?this.workerVirtualTaskRunTime=e+this.getWorkerTaskRunTime(this.nextWorkerNodeKey):(this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:this.nextWorkerNodeKey+1,this.workerVirtualTaskRunTime=0),this.nextWorkerNodeKey}}class z{workerChoiceStrategy;workerChoiceStrategies;constructor(e,t=N.ROUND_ROBIN,s=g){this.workerChoiceStrategy=t,this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[N.ROUND_ROBIN,new(v.bind(this))(e,s)],[N.LEAST_USED,new(C.bind(this))(e,s)],[N.LEAST_BUSY,new(b.bind(this))(e,s)],[N.LEAST_ELU,new(R.bind(this))(e,s)],[N.FAIR_SHARE,new(E.bind(this))(e,s)],[N.WEIGHTED_ROUND_ROBIN,new(O.bind(this))(e,s)],[N.INTERLEAVED_WEIGHTED_ROUND_ROBIN,new(I.bind(this))(e,s)]])}getStrategyPolicy(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).strategyPolicy}getTaskStatisticsRequirements(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).taskStatisticsRequirements}setWorkerChoiceStrategy(e){this.workerChoiceStrategy!==e&&(this.workerChoiceStrategy=e),this.workerChoiceStrategies.get(this.workerChoiceStrategy)?.reset()}update(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).update(e)}execute(){const e=this.workerChoiceStrategies.get(this.workerChoiceStrategy).choose();if(null==e)throw new TypeError("Worker node key chosen is null or undefined");return e}remove(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).remove(e)}setOptions(e){for(const t of this.workerChoiceStrategies.values())t.setOptions(e)}}class M extends Array{size;constructor(e=1024,...t){super(),this.checkSize(e),this.size=e,arguments.length>1&&this.push(...t)}push(...e){const t=super.push(...e);return t>this.size&&super.splice(0,t-this.size),this.length}unshift(...e){return super.unshift(...e)>this.size&&super.splice(this.size,e.length),this.length}concat(...e){const t=super.concat(e);return t.size=this.size,t.length>t.size&&t.splice(0,t.length-t.size),t}splice(e,t,...s){let r=[];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 M(r.length+e.length,...r,...e)}}else r=2===arguments.length?super.splice(e,t):super.splice(e);return r}resize(e){if(this.checkSize(e),0===e)this.length=0;else if(e<this.size)for(let t=e;t<this.size;t++)super.pop();this.size=e}empty(){return 0===this.length}full(){return this.length===this.size}checkSize(e){if(!Number.isSafeInteger(e))throw new TypeError(`Invalid circular array size: ${e} is not a safe integer`);if(e<0)throw new RangeError(`Invalid circular array size: ${e} < 0`)}}class q{items;offset;size;maxSize;constructor(){this.clear()}enqueue(e){return this.items.push(e),++this.size,this.size>this.maxSize&&(this.maxSize=this.size),this.size}dequeue(){if(this.size<=0)return;const e=this.items[this.offset];return 2*++this.offset>=this.items.length&&(this.items=this.items.slice(this.offset),this.offset=0),--this.size,e}peek(){if(!(this.size<=0))return this.items[this.offset]}clear(){this.items=[],this.offset=0,this.size=0,this.maxSize=0}[Symbol.iterator](){const e=this.items;let t=this.offset;return{next:()=>{if(t>=e.length)return{value:void 0,done:!0};const s=e[t];return++t,{value:s,done:!1}}}}}const K=Object.freeze({thread:"thread",cluster:"cluster"});class Q{worker;info;usage;tasksUsage;tasksQueue;constructor(e,t){this.worker=e,this.info=this.initWorkerInfo(e,t),this.usage=this.initWorkerUsage(),this.tasksUsage=new Map,this.tasksQueue=new q}tasksQueueSize(){return this.tasksQueue.size}tasksQueueMaxSize(){return this.tasksQueue.maxSize}enqueueTask(e){return this.tasksQueue.enqueue(e)}dequeueTask(){return this.tasksQueue.dequeue()}clearTasksQueue(){this.tasksQueue.clear()}resetUsage(){this.usage=this.initWorkerUsage(),this.tasksUsage.clear()}closeChannel(){null!=this.info.messageChannel&&(this.info.messageChannel?.port1.unref(),this.info.messageChannel?.port2.unref(),this.info.messageChannel?.port1.close(),this.info.messageChannel?.port2.close(),delete this.info.messageChannel)}getTaskWorkerUsage(e){return this.tasksUsage.has(e)||this.tasksUsage.set(e,this.initTaskWorkerUsage(e)),this.tasksUsage.get(e)}initWorkerInfo(e,s){return{id:this.getWorkerId(e,s),type:s,dynamic:!1,ready:!1,...s===K.thread&&{messageChannel:new t.MessageChannel}}}initWorkerUsage(){const e=()=>this.tasksQueueSize(),t=()=>this.tasksQueueMaxSize();return{tasks:{executed:0,executing:0,get queued(){return e()},get maxQueued(){return t()},failed:0},runTime:{history:new M},waitTime:{history:new M},elu:{idle:{history:new M},active:{history:new M}}}}initTaskWorkerUsage(e){const t=()=>{let t=0;for(const s of this.tasksQueue)s.name===e&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},failed:0},runTime:{history:new M},waitTime:{history:new M},elu:{idle:{history:new M},active:{history:new M}}}}getWorkerId(e,t){return t===K.thread?e.threadId:t===K.cluster?e.id:void 0}}class A{numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;starting;startTimestamp;constructor(e,t,s){if(this.numberOfWorkers=e,this.filePath=t,this.opts=s,!this.isMain())throw new Error("Cannot start a pool from a worker!");this.checkNumberOfWorkers(this.numberOfWorkers),this.checkFilePath(this.filePath),this.checkPoolOptions(this.opts),this.chooseWorkerNode=this.chooseWorkerNode.bind(this),this.executeTask=this.executeTask.bind(this),this.enqueueTask=this.enqueueTask.bind(this),this.dequeueTask=this.dequeueTask.bind(this),this.checkAndEmitEvents=this.checkAndEmitEvents.bind(this),!0===this.opts.enableEvents&&(this.emitter=new c),this.workerChoiceStrategyContext=new z(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook(),this.starting=!0,this.startPool(),this.starting=!1,this.startTimestamp=i.performance.now()}checkFilePath(e){if(null==e||"string"!=typeof e||"string"==typeof e&&0===e.trim().length)throw new Error("Please specify a file with a worker implementation");if(!o.existsSync(e))throw new Error(`Cannot find the worker file '${e}'`)}checkNumberOfWorkers(e){if(null==e)throw new Error("Cannot instantiate a pool without specifying the number of workers");if(!Number.isSafeInteger(e))throw new TypeError("Cannot instantiate a pool with a non safe integer number of workers");if(e<0)throw new RangeError("Cannot instantiate a pool with a negative number of workers");if(this.type===k.fixed&&0===e)throw new RangeError("Cannot instantiate a fixed pool with zero worker")}checkDynamicPoolSize(e,t){if(this.type===k.dynamic){if(null==t)throw new Error("Cannot instantiate a dynamic pool without specifying the maximum pool size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot instantiate a dynamic pool with a non safe integer maximum pool size");if(e>t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size");if(0===t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size equal to zero");if(e===t)throw new RangeError("Cannot instantiate a dynamic pool with a minimum pool size equal to the maximum pool size. Use a fixed pool instead")}}checkPoolOptions(e){if(!f(e))throw new TypeError("Invalid pool options: must be a plain object");this.opts.workerChoiceStrategy=e.workerChoiceStrategy??N.ROUND_ROBIN,this.checkValidWorkerChoiceStrategy(this.opts.workerChoiceStrategy),this.opts.workerChoiceStrategyOptions=e.workerChoiceStrategyOptions??g,this.checkValidWorkerChoiceStrategyOptions(this.opts.workerChoiceStrategyOptions),this.opts.restartWorkerOnError=e.restartWorkerOnError??!0,this.opts.enableEvents=e.enableEvents??!0,this.opts.enableTasksQueue=e.enableTasksQueue??!1,this.opts.enableTasksQueue&&(this.checkValidTasksQueueOptions(e.tasksQueueOptions),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e.tasksQueueOptions))}checkValidWorkerChoiceStrategy(e){if(!Object.values(N).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)}checkValidWorkerChoiceStrategyOptions(e){if(!f(e))throw new TypeError("Invalid worker choice strategy options: must be a plain object");if(null!=e.weights&&Object.keys(e.weights).length!==this.maxSize)throw new Error("Invalid worker choice strategy options: must have a weight for each worker node");if(null!=e.measurement&&!Object.values(x).includes(e.measurement))throw new Error(`Invalid worker choice strategy options: invalid measurement '${e.measurement}'`)}checkValidTasksQueueOptions(e){if(null!=e&&!f(e))throw new TypeError("Invalid tasks queue options: must be a plain object");if(null!=e?.concurrency&&!Number.isSafeInteger(e.concurrency))throw new TypeError("Invalid worker tasks concurrency: must be an integer");if(null!=e?.concurrency&&e.concurrency<=0)throw new Error(`Invalid worker tasks concurrency '${e.concurrency}'`)}startPool(){for(;this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.numberOfWorkers;)this.createAndSetupWorkerNode()}get info(){return{version:"2.6.24",type:this.type,worker:this.worker,ready:this.ready,strategy:this.opts.workerChoiceStrategy,minSize:this.minSize,maxSize:this.maxSize,...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{utilization:y(this.utilization)},workerNodes:this.workerNodes.length,idleWorkerNodes:this.workerNodes.reduce(((e,t)=>0===t.usage.tasks.executing?e+1:e),0),busyWorkerNodes:this.workerNodes.reduce(((e,t)=>t.usage.tasks.executing>0?e+1:e),0),executedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executed),0),executingTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executing),0),...!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)},failedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.failed),0),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&{runTime:{minimum:y(Math.min(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:y(Math.max(...this.workerNodes.map((e=>e.usage.runTime?.maximum??-1/0)))),average:y(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)/this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.executed??0)),0)),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&{median:y(w(this.workerNodes.map((e=>e.usage.runTime?.median??0))))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:y(Math.min(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:y(Math.max(...this.workerNodes.map((e=>e.usage.waitTime?.maximum??-1/0)))),average:y(this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0)/this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.executed??0)),0)),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&{median:y(w(this.workerNodes.map((e=>e.usage.waitTime?.median??0))))}}}}}get ready(){return this.workerNodes.reduce(((e,t)=>!t.info.dynamic&&t.info.ready?e+1:e),0)>=this.minSize}get utilization(){const e=(i.performance.now()-this.startTimestamp)*this.maxSize;return(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)+this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0))/e}checkMessageWorkerId(e){if(null!=e.workerId&&-1===this.getWorkerNodeKeyByWorkerId(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKeyByWorker(e){return this.workerNodes.findIndex((t=>t.worker===e))}getWorkerNodeKeyByWorkerId(e){return this.workerNodes.findIndex((t=>t.info.id===e))}setWorkerChoiceStrategy(e,t){this.checkValidWorkerChoiceStrategy(e),this.opts.workerChoiceStrategy=e,this.workerChoiceStrategyContext.setWorkerChoiceStrategy(this.opts.workerChoiceStrategy),null!=t&&this.setWorkerChoiceStrategyOptions(t);for(const[e,t]of this.workerNodes.entries())t.resetUsage(),this.sendWorkerStatisticsMessageToWorker(e)}setWorkerChoiceStrategyOptions(e){this.checkValidWorkerChoiceStrategyOptions(e),this.opts.workerChoiceStrategyOptions=e,this.workerChoiceStrategyContext.setOptions(this.opts.workerChoiceStrategyOptions)}enableTasksQueue(e,t){!0!==this.opts.enableTasksQueue||e||this.flushTasksQueues(),this.opts.enableTasksQueue=e,this.setTasksQueueOptions(t)}setTasksQueueOptions(e){!0===this.opts.enableTasksQueue?(this.checkValidTasksQueueOptions(e),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e)):null!=this.opts.tasksQueueOptions&&delete this.opts.tasksQueueOptions}buildTasksQueueOptions(e){return{concurrency:e?.concurrency??1}}get full(){return this.workerNodes.length>=this.maxSize}internalBusy(){return!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))}async execute(e,t,s){return await new Promise(((o,n)=>{null!=t&&"string"!=typeof t&&n(new TypeError("name argument must be a string")),null==s||Array.isArray(s)||n(new TypeError("transferList argument must be an array"));const a=i.performance.now(),h=this.chooseWorkerNode(),u={name:t??l,data:e??{},transferList:s,timestamp:a,workerId:this.getWorkerInfo(h).id,taskId:r.randomUUID()};this.promiseResponseMap.set(u.taskId,{resolve:o,reject:n,workerNodeKey:h}),!1===this.opts.enableTasksQueue||!0===this.opts.enableTasksQueue&&this.workerNodes[h].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency?this.executeTask(h,u):this.enqueueTask(h,u),this.checkAndEmitEvents()}))}async destroy(){await Promise.all(this.workerNodes.map((async(e,t)=>{await this.destroyWorkerNode(t)})))}setupHook(){}beforeTaskExecutionHook(e,t){const s=this.workerNodes[e].usage;++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t);const r=this.workerNodes[e].getTaskWorkerUsage(t.name);++r.tasks.executing,this.updateWaitTimeWorkerUsage(r,t)}afterTaskExecutionHook(e,t){const s=this.workerNodes[e].usage;this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t);const r=this.workerNodes[e].getTaskWorkerUsage(t.taskPerformance?.name??l);this.updateTaskStatisticsWorkerUsage(r,t),this.updateRunTimeWorkerUsage(r,t),this.updateEluWorkerUsage(r,t)}updateTaskStatisticsWorkerUsage(e,t){const s=e.tasks;--s.executing,null==t.taskError?++s.executed:++s.failed}updateRunTimeWorkerUsage(e,t){T(e.runTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime,t.taskPerformance?.runTime??0,e.tasks.executed)}updateWaitTimeWorkerUsage(e,t){const s=i.performance.now(),r=s-(t.timestamp??s);T(e.waitTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime,r,e.tasks.executed)}updateEluWorkerUsage(e,t){const s=this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu;T(e.elu.active,s,t.taskPerformance?.elu?.active??0,e.tasks.executed),T(e.elu.idle,s,t.taskPerformance?.elu?.idle??0,e.tasks.executed),s.aggregate&&null!=t.taskPerformance?.elu&&(null!=e.elu.utilization?e.elu.utilization=(e.elu.utilization+t.taskPerformance.elu.utilization)/2:e.elu.utilization=t.taskPerformance.elu.utilization)}chooseWorkerNode(){if(this.shallCreateDynamicWorker()){const e=this.createAndSetupDynamicWorkerNode();if(this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker)return e}return this.workerChoiceStrategyContext.execute()}shallCreateDynamicWorker(){return this.type===k.dynamic&&!this.full&&this.internalBusy()}createAndSetupWorkerNode(){const e=this.createWorker();e.on("message",this.opts.messageHandler??m),e.on("error",this.opts.errorHandler??m),e.on("error",(t=>{const s=this.getWorkerNodeKeyByWorker(e),r=this.getWorkerInfo(s);r.ready=!1,this.workerNodes[s].closeChannel(),this.emitter?.emit(d.error,t),!0!==this.opts.restartWorkerOnError||this.starting||(r.dynamic?this.createAndSetupDynamicWorkerNode():this.createAndSetupWorkerNode()),!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(s)})),e.on("online",this.opts.onlineHandler??m),e.on("exit",this.opts.exitHandler??m),e.once("exit",(()=>{this.removeWorkerNode(e)}));const t=this.addWorkerNode(e);return this.afterWorkerNodeSetup(t),t}createAndSetupDynamicWorkerNode(){const e=this.createAndSetupWorkerNode();this.registerWorkerMessageListener(e,(e=>{const t=this.getWorkerNodeKeyByWorkerId(e.workerId),s=this.workerNodes[t].usage;var r;r=W.HARD,(e.kill===r||null!=e.kill&&(!1===this.opts.enableTasksQueue&&0===s.tasks.executing||!0===this.opts.enableTasksQueue&&0===s.tasks.executing&&0===this.tasksQueueSize(t)))&&this.destroyWorkerNode(t).catch(m)}));const t=this.getWorkerInfo(e);return this.sendToWorker(e,{checkActive:!0,workerId:t.id}),t.dynamic=!0,this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker&&(t.ready=!0),e}afterWorkerNodeSetup(e){this.registerWorkerMessageListener(e,this.workerListener()),this.sendStartupMessageToWorker(e),this.sendWorkerStatisticsMessageToWorker(e)}sendWorkerStatisticsMessageToWorker(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate},workerId:this.getWorkerInfo(e).id})}redistributeQueuedTasks(e){for(;this.tasksQueueSize(e)>0;){let t=e,s=1/0,r=!1;for(const[i,o]of this.workerNodes.entries()){const n=this.getWorkerInfo(i);if(i!==e&&n.ready&&0===o.usage.tasks.queued){this.workerNodes[i].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&(r=!0),t=i;break}i!==e&&n.ready&&o.usage.tasks.queued<s&&(s=o.usage.tasks.queued,t=i)}r?this.executeTask(t,this.dequeueTask(e)):this.enqueueTask(t,this.dequeueTask(e))}}workerListener(){return e=>{this.checkMessageWorkerId(e),null!=e.ready?this.handleWorkerReadyResponse(e):null!=e.taskId&&this.handleTaskExecutionResponse(e)}}handleWorkerReadyResponse(e){this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId)).ready=e.ready,null!=this.emitter&&this.ready&&this.emitter.emit(d.ready,this.info)}handleTaskExecutionResponse(e){const t=this.promiseResponseMap.get(e.taskId);if(null!=t){null!=e.taskError?(this.emitter?.emit(d.taskError,e.taskError),t.reject(e.taskError.message)):t.resolve(e.data);const s=t.workerNodeKey;this.afterTaskExecutionHook(s,e),this.promiseResponseMap.delete(e.taskId),!0===this.opts.enableTasksQueue&&this.tasksQueueSize(s)>0&&this.workerNodes[s].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&this.executeTask(s,this.dequeueTask(s)),this.workerChoiceStrategyContext.update(s)}}checkAndEmitEvents(){null!=this.emitter&&(this.busy&&this.emitter.emit(d.busy,this.info),this.type===k.dynamic&&this.full&&this.emitter.emit(d.full,this.info))}getWorkerInfo(e){return this.workerNodes[e].info}addWorkerNode(e){const t=new Q(e,this.worker);this.starting&&(t.info.ready=!0),this.workerNodes.push(t);const s=this.getWorkerNodeKeyByWorker(e);if(-1===s)throw new Error("Worker node not found");return s}removeWorkerNode(e){const t=this.getWorkerNodeKeyByWorker(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategyContext.remove(t))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(e,t,t.transferList)}enqueueTask(e,t){return this.workerNodes[e].enqueueTask(t)}dequeueTask(e){return this.workerNodes[e].dequeueTask()}tasksQueueSize(e){return this.workerNodes[e].tasksQueueSize()}flushTasksQueue(e){for(;this.tasksQueueSize(e)>0;)this.executeTask(e,this.dequeueTask(e));this.workerNodes[e].clearTasksQueue()}flushTasksQueues(){for(const[e]of this.workerNodes.entries())this.flushTasksQueue(e)}}class P extends A{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}setupHook(){s.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return s.isPrimary}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e].worker,s=new Promise((e=>{t.on("exit",(()=>{e()}))}));t.on("disconnect",(()=>{t.kill()})),this.sendToWorker(e,{kill:!0,workerId:t.id}),t.disconnect(),await s}sendToWorker(e,t){this.workerNodes[e].worker.send(t)}sendStartupMessageToWorker(e){this.sendToWorker(e,{ready:!1,workerId:this.workerNodes[e].worker.id})}registerWorkerMessageListener(e,t){this.workerNodes[e].worker.on("message",t)}createWorker(){return s.fork(this.opts.env)}get type(){return k.fixed}get worker(){return K.cluster}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}class U extends A{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}isMain(){return t.isMainThread}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e],s=t.worker,r=new Promise((e=>{s.on("exit",(()=>{e()}))}));this.sendToWorker(e,{kill:!0,workerId:s.threadId}),t.closeChannel(),await s.terminate(),await r}sendToWorker(e,t,s){this.getWorkerInfo(e).messageChannel.port1.postMessage(t,s)}sendStartupMessageToWorker(e){const t=this.workerNodes[e].worker,s=this.getWorkerInfo(e).messageChannel.port2;t.postMessage({ready:!1,workerId:t.threadId,port:s},[s])}registerWorkerMessageListener(e,t){this.getWorkerInfo(e).messageChannel.port1.on("message",t)}createWorker(){return new t.Worker(this.filePath,{env:t.SHARE_ENV,...this.opts.workerOptions})}get type(){return k.fixed}get worker(){return K.thread}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}const D=6e4,F=W.SOFT;class _ extends a.AsyncResource{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,s,r,i={killBehavior:F,maxInactiveTime:D}){super(e),this.isMain=t,this.mainWorker=s,this.opts=i,this.checkWorkerOptions(this.opts),this.checkTaskFunctions(r),this.isMain||this.getMainWorker()?.on("message",this.handleReadyMessage.bind(this))}checkWorkerOptions(e){this.opts.killBehavior=e.killBehavior??F,this.opts.maxInactiveTime=e.maxInactiveTime??D,delete this.opts.async}checkTaskFunctions(e){if(null==e)throw new Error("taskFunctions parameter is mandatory");if(this.taskFunctions=new Map,"function"==typeof e){const t=e.bind(this);this.taskFunctions.set(l,t),this.taskFunctions.set("string"==typeof e.name&&e.name.trim().length>0?e.name:"fn1",t)}else{if(!f(e))throw new TypeError("taskFunctions parameter is not a function or a plain object");{let t=!0;for(const[s,r]of Object.entries(e)){if("string"!=typeof s)throw new TypeError("A taskFunctions parameter object key is not a string");if("function"!=typeof r)throw new TypeError("A taskFunctions parameter object value is not a function");const e=r.bind(this);t&&(this.taskFunctions.set(l,e),t=!1),this.taskFunctions.set(s,e)}if(t)throw new Error("taskFunctions parameter object is empty")}}}hasTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");return this.taskFunctions.has(e)}addTaskFunction(e,t){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===l)throw new Error("Cannot add a task function with the default reserved name");if("function"!=typeof t)throw new TypeError("fn parameter is not a function");try{const s=t.bind(this);return this.taskFunctions.get(e)===this.taskFunctions.get(l)&&this.taskFunctions.set(l,s),this.taskFunctions.set(e,s),!0}catch{return!1}}removeTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===l)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(l))throw new Error("Cannot remove the task function used as the default task function");return this.taskFunctions.delete(e)}listTaskFunctions(){return[...this.taskFunctions.keys()]}setDefaultTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===l)throw new Error("Cannot set the default task function reserved name as the default task function");if(!this.taskFunctions.has(e))throw new Error("Cannot set the default task function to a non-existing task function");try{return this.taskFunctions.set(l,this.taskFunctions.get(e)),!0}catch{return!1}}messageListener(e){if(null!=e.workerId&&e.workerId!==this.id)throw new Error("Message worker id does not match worker id");e.workerId===this.id&&(null!=e.statistics?this.statistics=e.statistics:null!=e.checkActive?!this.isMain&&e.checkActive?this.startCheckActive():this.stopCheckActive():null!=e.taskId&&null!=e.data?this.run(e):!0===e.kill&&this.handleKillMessage(e))}handleKillMessage(e){!this.isMain&&this.stopCheckActive(),this.emitDestroy()}startCheckActive(){this.lastTaskTimestamp=i.performance.now(),this.activeInterval=setInterval(this.checkActive.bind(this),(this.opts.maxInactiveTime??D)/2)}stopCheckActive(){null!=this.activeInterval&&(clearInterval(this.activeInterval),delete this.activeInterval)}checkActive(){i.performance.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??D)&&this.sendToMainWorker({kill:this.opts.killBehavior,workerId:this.id})}getMainWorker(){if(null==this.mainWorker)throw new Error("Main worker not set");return this.mainWorker}handleError(e){return e instanceof Error?e.message:e}run(e){if(this.isMain)throw new Error("Cannot run a task in the main worker");const t=this.getTaskFunction(e.name);(e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name)(t)?this.runInAsyncScope(this.runAsync.bind(this),this,t,e):this.runInAsyncScope(this.runSync.bind(this),this,t,e)}runSync(e,t){try{let s=this.beginTaskPerformance(t.name);const r=e(t.data);s=this.endTaskPerformance(s),this.sendToMainWorker({data:r,taskPerformance:s,workerId:this.id,taskId:t.taskId})}catch(e){const s=this.handleError(e);this.sendToMainWorker({taskError:{name:t.name??l,message:s,data:t.data},workerId:this.id,taskId:t.taskId})}finally{this.updateLastTaskTimestamp()}}runAsync(e,t){let s=this.beginTaskPerformance(t.name);e(t.data).then((e=>(s=this.endTaskPerformance(s),this.sendToMainWorker({data:e,taskPerformance:s,workerId:this.id,taskId:t.taskId}),null))).catch((e=>{const s=this.handleError(e);this.sendToMainWorker({taskError:{name:t.name??l,message:s,data:t.data},workerId:this.id,taskId:t.taskId})})).finally((()=>{this.updateLastTaskTimestamp()})).catch(m)}getTaskFunction(e){e=e??l;const t=this.taskFunctions.get(e);if(null==t)throw new Error(`Task function '${e}' not found`);return t}beginTaskPerformance(e){return this.checkStatistics(),{name:e??l,timestamp:i.performance.now(),...this.statistics.elu&&{elu:i.performance.eventLoopUtilization()}}}endTaskPerformance(e){return this.checkStatistics(),{...e,...this.statistics.runTime&&{runTime:i.performance.now()-e.timestamp},...this.statistics.elu&&{elu:i.performance.eventLoopUtilization(e.elu)}}}checkStatistics(){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set")}updateLastTaskTimestamp(){this.isMain||null==this.activeInterval||(this.lastTaskTimestamp=i.performance.now())}}exports.ClusterWorker=class extends _{constructor(e,t={}){super("worker-cluster-pool:poolifier",s.isPrimary,s.worker,e,t)}handleReadyMessage(e){this.isMain||e.workerId!==this.id||null==e.ready||(this.getMainWorker()?.on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,workerId:this.id}))}get id(){return this.getMainWorker().id}sendToMainWorker(e){this.getMainWorker().send(e)}},exports.DynamicClusterPool=class extends P{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return k.dynamic}get maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}},exports.DynamicThreadPool=class extends U{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return k.dynamic}get maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}},exports.FixedClusterPool=P,exports.FixedThreadPool=U,exports.KillBehaviors=W,exports.Measurements=x,exports.PoolEvents=d,exports.PoolTypes=k,exports.ThreadWorker=class extends _{port;constructor(e,s={}){super("worker-thread-pool:poolifier",t.isMainThread,t.parentPort,e,s)}handleReadyMessage(e){this.isMain||e.workerId!==this.id||null==e.ready||null==e.port||(this.port=e.port,this.port.on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,workerId:this.id}))}handleKillMessage(e){super.handleKillMessage(e),this.port?.unref(),this.port?.close()}get id(){return t.threadId}sendToMainWorker(e){this.port.postMessage(e)}handleError(e){return e}},exports.WorkerChoiceStrategies=N,exports.WorkerTypes=K,exports.availableParallelism=()=>{let e=1;try{e=u.availableParallelism()}catch{const t=u.cpus();Array.isArray(t)&&t.length>0&&(e=t.length)}return e};
|
|
1
|
+
"use strict";var e=require("node:events"),t=require("node:worker_threads"),s=require("node:cluster"),r=require("node:crypto"),i=require("node:perf_hooks"),o=require("node:fs"),n=require("node:os"),a=require("node:async_hooks");function h(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(s){if("default"!==s){var r=Object.getOwnPropertyDescriptor(e,s);Object.defineProperty(t,s,r.get?r:{enumerable:!0,get:function(){return e[s]}})}})),t.default=e,Object.freeze(t)}var u=h(n);const k=Object.freeze({fixed:"fixed",dynamic:"dynamic"});class c extends e.EventEmitter{}const d=Object.freeze({full:"full",ready:"ready",busy:"busy",error:"error",taskError:"taskError"}),l="default",m=Object.freeze((()=>{})),g={runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},p={aggregate:!1,average:!1,median:!1},w=e=>{if(Array.isArray(e)&&0===e.length)return 0;if(Array.isArray(e)&&1===e.length)return e[0];const t=e.slice().sort(((e,t)=>e-t));return(t[t.length-1>>1]+t[t.length>>1])/2},y=(e,t=2)=>{const s=Math.pow(10,t);return Math.round(e*s*(1+Number.EPSILON))/s},f=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),T=(e,t)=>t===e,W=e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name,N=(e,t,s,r)=>{t.aggregate&&(e.aggregate=(e.aggregate??0)+s,e.minimum=Math.min(s,e.minimum??1/0),e.maximum=Math.max(s,e.maximum??-1/0),t.average&&0!==r&&(e.average=e.aggregate/r),t.median&&null!=s&&(e.history.push(s),e.median=w(e.history)))},x=Object.freeze({SOFT:"SOFT",HARD:"HARD"}),S=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"}),E=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"});class I{pool;opts;nextWorkerNodeKey=0;strategyPolicy={useDynamicWorker:!1};taskStatisticsRequirements={runTime:p,waitTime:p,elu:p};constructor(e,t=g){this.pool=e,this.opts=t,this.choose=this.choose.bind(this)}setTaskStatisticsRequirements(e){this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.runTime,e.runTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.waitTime,e.waitTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.elu,e.elu?.median)}toggleMedianMeasurementStatisticsRequirements(e,t){e.average&&t&&(e.average=!1,e.median=t),e.median&&!t&&(e.average=!0,e.median=t)}setOptions(e){this.opts=e??g,this.setTaskStatisticsRequirements(this.opts)}isWorkerNodeReady(e){return this.pool.workerNodes[e].info.ready}getWorkerTaskRunTime(e){return this.taskStatisticsRequirements.runTime.median?this.pool.workerNodes[e].usage.runTime?.median??0:this.pool.workerNodes[e].usage.runTime?.average??0}getWorkerTaskWaitTime(e){return this.taskStatisticsRequirements.waitTime.median?this.pool.workerNodes[e].usage.waitTime?.median??0:this.pool.workerNodes[e].usage.waitTime?.average??0}getWorkerTaskElu(e){return this.taskStatisticsRequirements.elu.median?this.pool.workerNodes[e].usage.elu.active?.median??0:this.pool.workerNodes[e].usage.elu.active?.average??0}computeDefaultWorkerWeight(){let e=0;for(const t of n.cpus()){const s=t.speed.toString().length-1;e+=1/(t.speed/Math.pow(10,s))*Math.pow(10,s)}return Math.round(e/n.cpus().length)}}class b extends I{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:p,elu:{aggregate:!0,average:!0,median:!1}};workersVirtualTaskEndTimestamp=[];constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.workersVirtualTaskEndTimestamp=[],!0}update(e){return this.computeWorkerVirtualTaskEndTimestamp(e),!0}choose(){return this.fairShareNextWorkerNodeKey()}remove(e){return this.workersVirtualTaskEndTimestamp.splice(e,1),!0}fairShareNextWorkerNodeKey(){let e=1/0;for(const[t]of this.pool.workerNodes.entries()){null==this.workersVirtualTaskEndTimestamp[t]&&this.computeWorkerVirtualTaskEndTimestamp(t);const s=this.workersVirtualTaskEndTimestamp[t];this.isWorkerNodeReady(t)&&s<e&&(e=s,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}computeWorkerVirtualTaskEndTimestamp(e){this.workersVirtualTaskEndTimestamp[e]=this.getWorkerVirtualTaskEndTimestamp(e,this.getWorkerVirtualTaskStartTimestamp(e))}getWorkerVirtualTaskEndTimestamp(e,t){return t+(this.opts.measurement===E.elu?this.getWorkerTaskElu(e):this.getWorkerTaskRunTime(e))}getWorkerVirtualTaskStartTimestamp(e){return Math.max(performance.now(),this.workersVirtualTaskEndTimestamp[e]??-1/0)}}class C extends I{strategyPolicy={useDynamicWorker:!0};roundId=0;roundWeights;defaultWorkerWeight;constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight(),this.roundWeights=this.getRoundWeights()}reset(){return this.nextWorkerNodeKey=0,this.roundId=0,!0}update(){return!0}choose(){let e,t;for(let s=this.roundId;s<this.roundWeights.length;s++)for(let r=this.nextWorkerNodeKey;r<this.pool.workerNodes.length;r++){const i=this.opts.weights?.[r]??this.defaultWorkerWeight;if(this.isWorkerNodeReady(r)&&i>=this.roundWeights[s]){e=s,t=r;break}}this.roundId=e??0,this.nextWorkerNodeKey=t??0;const s=this.nextWorkerNodeKey;return this.nextWorkerNodeKey===this.pool.workerNodes.length-1?(this.nextWorkerNodeKey=0,this.roundId=this.roundId===this.roundWeights.length-1?0:this.roundId+1):this.nextWorkerNodeKey=this.nextWorkerNodeKey+1,s}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1,this.roundId=this.roundId===this.roundWeights.length-1?0:this.roundId+1)),!0}setOptions(e){super.setOptions(e),this.roundWeights=this.getRoundWeights()}getRoundWeights(){return null==this.opts.weights?[this.defaultWorkerWeight]:[...new Set(Object.values(this.opts.weights).slice().sort(((e,t)=>e-t)))]}}class R extends I{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:p};constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.leastBusyNextWorkerNodeKey()}remove(){return!0}leastBusyNextWorkerNodeKey(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=(s.usage.runTime?.aggregate??0)+(s.usage.waitTime?.aggregate??0);if(this.isWorkerNodeReady(t)&&0===r){this.nextWorkerNodeKey=t;break}this.isWorkerNodeReady(t)&&r<e&&(e=r,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}}class v extends I{constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.leastUsedNextWorkerNodeKey()}remove(){return!0}leastUsedNextWorkerNodeKey(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=s.usage.tasks,i=r.executed+r.executing+r.queued;if(this.isWorkerNodeReady(t)&&0===i){this.nextWorkerNodeKey=t;break}this.isWorkerNodeReady(t)&&i<e&&(e=i,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}}class O extends I{taskStatisticsRequirements={runTime:p,waitTime:p,elu:{aggregate:!0,average:!1,median:!1}};constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.leastEluNextWorkerNodeKey()}remove(){return!0}leastEluNextWorkerNodeKey(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=s.usage,i=r.elu?.active?.aggregate??0;if(this.isWorkerNodeReady(t)&&0===i){this.nextWorkerNodeKey=t;break}this.isWorkerNodeReady(t)&&i<e&&(e=i,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}}class M extends I{strategyPolicy={useDynamicWorker:!0};constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.nextWorkerNodeKey=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;do{this.roundRobinNextWorkerNodeKey()}while(!this.isWorkerNodeReady(this.nextWorkerNodeKey));return e}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1)),!0}roundRobinNextWorkerNodeKey(){return this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:this.nextWorkerNodeKey+1,this.nextWorkerNodeKey}}class z extends I{strategyPolicy={useDynamicWorker:!0};taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:p,elu:p};defaultWorkerWeight;workerVirtualTaskRunTime=0;constructor(e,t=g){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight()}reset(){return this.nextWorkerNodeKey=0,this.workerVirtualTaskRunTime=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;do{this.weightedRoundRobinNextWorkerNodeKey()}while(!this.isWorkerNodeReady(this.nextWorkerNodeKey));return e}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1),this.workerVirtualTaskRunTime=0),!0}weightedRoundRobinNextWorkerNodeKey(){const e=this.workerVirtualTaskRunTime;return e<(this.opts.weights?.[this.nextWorkerNodeKey]??this.defaultWorkerWeight)?this.workerVirtualTaskRunTime=e+this.getWorkerTaskRunTime(this.nextWorkerNodeKey):(this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:this.nextWorkerNodeKey+1,this.workerVirtualTaskRunTime=0),this.nextWorkerNodeKey}}class K{workerChoiceStrategy;workerChoiceStrategies;constructor(e,t=S.ROUND_ROBIN,s=g){this.workerChoiceStrategy=t,this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[S.ROUND_ROBIN,new(M.bind(this))(e,s)],[S.LEAST_USED,new(v.bind(this))(e,s)],[S.LEAST_BUSY,new(R.bind(this))(e,s)],[S.LEAST_ELU,new(O.bind(this))(e,s)],[S.FAIR_SHARE,new(b.bind(this))(e,s)],[S.WEIGHTED_ROUND_ROBIN,new(z.bind(this))(e,s)],[S.INTERLEAVED_WEIGHTED_ROUND_ROBIN,new(C.bind(this))(e,s)]])}getStrategyPolicy(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).strategyPolicy}getTaskStatisticsRequirements(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).taskStatisticsRequirements}setWorkerChoiceStrategy(e){this.workerChoiceStrategy!==e&&(this.workerChoiceStrategy=e),this.workerChoiceStrategies.get(this.workerChoiceStrategy)?.reset()}update(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).update(e)}execute(){const e=this.workerChoiceStrategies.get(this.workerChoiceStrategy).choose();if(null==e)throw new TypeError("Worker node key chosen is null or undefined");return e}remove(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).remove(e)}setOptions(e){for(const t of this.workerChoiceStrategies.values())t.setOptions(e)}}class q extends Array{size;constructor(e=1024,...t){super(),this.checkSize(e),this.size=e,arguments.length>1&&this.push(...t)}push(...e){const t=super.push(...e);return t>this.size&&super.splice(0,t-this.size),this.length}unshift(...e){return super.unshift(...e)>this.size&&super.splice(this.size,e.length),this.length}concat(...e){const t=super.concat(e);return t.size=this.size,t.length>t.size&&t.splice(0,t.length-t.size),t}splice(e,t,...s){let r=[];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 q(r.length+e.length,...r,...e)}}else r=2===arguments.length?super.splice(e,t):super.splice(e);return r}resize(e){if(this.checkSize(e),0===e)this.length=0;else if(e<this.size)for(let t=e;t<this.size;t++)super.pop();this.size=e}empty(){return 0===this.length}full(){return this.length===this.size}checkSize(e){if(!Number.isSafeInteger(e))throw new TypeError(`Invalid circular array size: ${e} is not a safe integer`);if(e<0)throw new RangeError(`Invalid circular array size: ${e} < 0`)}}class Q{items;offset;size;maxSize;constructor(){this.clear()}enqueue(e){return this.items.push(e),++this.size,this.size>this.maxSize&&(this.maxSize=this.size),this.size}dequeue(){if(this.size<=0)return;const e=this.items[this.offset];return 2*++this.offset>=this.items.length&&(this.items=this.items.slice(this.offset),this.offset=0),--this.size,e}peek(){if(!(this.size<=0))return this.items[this.offset]}clear(){this.items=[],this.offset=0,this.size=0,this.maxSize=0}[Symbol.iterator](){const e=this.items;let t=this.offset;return{next:()=>{if(t>=e.length)return{value:void 0,done:!0};const s=e[t];return++t,{value:s,done:!1}}}}}const F=Object.freeze({thread:"thread",cluster:"cluster"});class A{worker;info;usage;tasksUsage;tasksQueue;constructor(e,t){this.worker=e,this.info=this.initWorkerInfo(e,t),this.usage=this.initWorkerUsage(),this.tasksUsage=new Map,this.tasksQueue=new Q}tasksQueueSize(){return this.tasksQueue.size}tasksQueueMaxSize(){return this.tasksQueue.maxSize}enqueueTask(e){return this.tasksQueue.enqueue(e)}dequeueTask(){return this.tasksQueue.dequeue()}clearTasksQueue(){this.tasksQueue.clear()}resetUsage(){this.usage=this.initWorkerUsage(),this.tasksUsage.clear()}closeChannel(){null!=this.info.messageChannel&&(this.info.messageChannel?.port1.unref(),this.info.messageChannel?.port2.unref(),this.info.messageChannel?.port1.close(),this.info.messageChannel?.port2.close(),delete this.info.messageChannel)}getTaskWorkerUsage(e){return this.tasksUsage.has(e)||this.tasksUsage.set(e,this.initTaskWorkerUsage(e)),this.tasksUsage.get(e)}initWorkerInfo(e,s){return{id:this.getWorkerId(e,s),type:s,dynamic:!1,ready:!1,...s===F.thread&&{messageChannel:new t.MessageChannel}}}initWorkerUsage(){const e=()=>this.tasksQueueSize(),t=()=>this.tasksQueueMaxSize();return{tasks:{executed:0,executing:0,get queued(){return e()},get maxQueued(){return t()},failed:0},runTime:{history:new q},waitTime:{history:new q},elu:{idle:{history:new q},active:{history:new q}}}}initTaskWorkerUsage(e){const t=()=>{let t=0;for(const s of this.tasksQueue)s.name===e&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},failed:0},runTime:{history:new q},waitTime:{history:new q},elu:{idle:{history:new q},active:{history:new q}}}}getWorkerId(e,t){return t===F.thread?e.threadId:t===F.cluster?e.id:void 0}}class P{numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;starting;startTimestamp;taskFunctions;constructor(e,t,s){if(this.numberOfWorkers=e,this.filePath=t,this.opts=s,!this.isMain())throw new Error("Cannot start a pool from a worker with the same type as the pool");this.checkNumberOfWorkers(this.numberOfWorkers),this.checkFilePath(this.filePath),this.checkPoolOptions(this.opts),this.chooseWorkerNode=this.chooseWorkerNode.bind(this),this.executeTask=this.executeTask.bind(this),this.enqueueTask=this.enqueueTask.bind(this),this.dequeueTask=this.dequeueTask.bind(this),this.checkAndEmitEvents=this.checkAndEmitEvents.bind(this),!0===this.opts.enableEvents&&(this.emitter=new c),this.workerChoiceStrategyContext=new K(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook(),this.starting=!0,this.startPool(),this.starting=!1,this.startTimestamp=i.performance.now()}checkFilePath(e){if(null==e||"string"!=typeof e||"string"==typeof e&&0===e.trim().length)throw new Error("Please specify a file with a worker implementation");if(!o.existsSync(e))throw new Error(`Cannot find the worker file '${e}'`)}checkNumberOfWorkers(e){if(null==e)throw new Error("Cannot instantiate a pool without specifying the number of workers");if(!Number.isSafeInteger(e))throw new TypeError("Cannot instantiate a pool with a non safe integer number of workers");if(e<0)throw new RangeError("Cannot instantiate a pool with a negative number of workers");if(this.type===k.fixed&&0===e)throw new RangeError("Cannot instantiate a fixed pool with zero worker")}checkDynamicPoolSize(e,t){if(this.type===k.dynamic){if(null==t)throw new Error("Cannot instantiate a dynamic pool without specifying the maximum pool size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot instantiate a dynamic pool with a non safe integer maximum pool size");if(e>t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size");if(0===t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size equal to zero");if(e===t)throw new RangeError("Cannot instantiate a dynamic pool with a minimum pool size equal to the maximum pool size. Use a fixed pool instead")}}checkPoolOptions(e){if(!f(e))throw new TypeError("Invalid pool options: must be a plain object");this.opts.workerChoiceStrategy=e.workerChoiceStrategy??S.ROUND_ROBIN,this.checkValidWorkerChoiceStrategy(this.opts.workerChoiceStrategy),this.opts.workerChoiceStrategyOptions=e.workerChoiceStrategyOptions??g,this.checkValidWorkerChoiceStrategyOptions(this.opts.workerChoiceStrategyOptions),this.opts.restartWorkerOnError=e.restartWorkerOnError??!0,this.opts.enableEvents=e.enableEvents??!0,this.opts.enableTasksQueue=e.enableTasksQueue??!1,this.opts.enableTasksQueue&&(this.checkValidTasksQueueOptions(e.tasksQueueOptions),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e.tasksQueueOptions))}checkValidWorkerChoiceStrategy(e){if(!Object.values(S).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)}checkValidWorkerChoiceStrategyOptions(e){if(!f(e))throw new TypeError("Invalid worker choice strategy options: must be a plain object");if(null!=e.weights&&Object.keys(e.weights).length!==this.maxSize)throw new Error("Invalid worker choice strategy options: must have a weight for each worker node");if(null!=e.measurement&&!Object.values(E).includes(e.measurement))throw new Error(`Invalid worker choice strategy options: invalid measurement '${e.measurement}'`)}checkValidTasksQueueOptions(e){if(null!=e&&!f(e))throw new TypeError("Invalid tasks queue options: must be a plain object");if(null!=e?.concurrency&&!Number.isSafeInteger(e.concurrency))throw new TypeError("Invalid worker tasks concurrency: must be an integer");if(null!=e?.concurrency&&e.concurrency<=0)throw new Error(`Invalid worker tasks concurrency '${e.concurrency}'`)}startPool(){for(;this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.numberOfWorkers;)this.createAndSetupWorkerNode()}get info(){return{version:"2.6.26",type:this.type,worker:this.worker,ready:this.ready,strategy:this.opts.workerChoiceStrategy,minSize:this.minSize,maxSize:this.maxSize,...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{utilization:y(this.utilization)},workerNodes:this.workerNodes.length,idleWorkerNodes:this.workerNodes.reduce(((e,t)=>0===t.usage.tasks.executing?e+1:e),0),busyWorkerNodes:this.workerNodes.reduce(((e,t)=>t.usage.tasks.executing>0?e+1:e),0),executedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executed),0),executingTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executing),0),...!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)},failedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.failed),0),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&{runTime:{minimum:y(Math.min(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:y(Math.max(...this.workerNodes.map((e=>e.usage.runTime?.maximum??-1/0)))),average:y(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)/this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.executed??0)),0)),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&{median:y(w(this.workerNodes.map((e=>e.usage.runTime?.median??0))))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:y(Math.min(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:y(Math.max(...this.workerNodes.map((e=>e.usage.waitTime?.maximum??-1/0)))),average:y(this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0)/this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.executed??0)),0)),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&{median:y(w(this.workerNodes.map((e=>e.usage.waitTime?.median??0))))}}}}}get ready(){return this.workerNodes.reduce(((e,t)=>!t.info.dynamic&&t.info.ready?e+1:e),0)>=this.minSize}get utilization(){const e=(i.performance.now()-this.startTimestamp)*this.maxSize;return(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)+this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0))/e}checkMessageWorkerId(e){if(null!=e.workerId&&-1===this.getWorkerNodeKeyByWorkerId(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKeyByWorker(e){return this.workerNodes.findIndex((t=>t.worker===e))}getWorkerNodeKeyByWorkerId(e){return this.workerNodes.findIndex((t=>t.info.id===e))}setWorkerChoiceStrategy(e,t){this.checkValidWorkerChoiceStrategy(e),this.opts.workerChoiceStrategy=e,this.workerChoiceStrategyContext.setWorkerChoiceStrategy(this.opts.workerChoiceStrategy),null!=t&&this.setWorkerChoiceStrategyOptions(t);for(const[e,t]of this.workerNodes.entries())t.resetUsage(),this.sendStatisticsMessageToWorker(e)}setWorkerChoiceStrategyOptions(e){this.checkValidWorkerChoiceStrategyOptions(e),this.opts.workerChoiceStrategyOptions=e,this.workerChoiceStrategyContext.setOptions(this.opts.workerChoiceStrategyOptions)}enableTasksQueue(e,t){!0!==this.opts.enableTasksQueue||e||this.flushTasksQueues(),this.opts.enableTasksQueue=e,this.setTasksQueueOptions(t)}setTasksQueueOptions(e){!0===this.opts.enableTasksQueue?(this.checkValidTasksQueueOptions(e),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e)):null!=this.opts.tasksQueueOptions&&delete this.opts.tasksQueueOptions}buildTasksQueueOptions(e){return{concurrency:e?.concurrency??1}}get full(){return this.workerNodes.length>=this.maxSize}internalBusy(){return!0===this.opts.enableTasksQueue?-1===this.workerNodes.findIndex((e=>e.info.ready&&e.usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency)):-1===this.workerNodes.findIndex((e=>e.info.ready&&0===e.usage.tasks.executing))}listTaskFunctions(){return null!=this.taskFunctions?this.taskFunctions:[]}async execute(e,t,s){return await new Promise(((o,n)=>{null!=t&&"string"!=typeof t&&n(new TypeError("name argument must be a string")),null!=t&&"string"==typeof t&&0===t.trim().length&&n(new TypeError("name argument must not be an empty string")),null==t||null==this.taskFunctions||this.taskFunctions.includes(t)||n(new Error(`Task function '${t}' is not registered in the pool`)),null==s||Array.isArray(s)||n(new TypeError("transferList argument must be an array"));const a=i.performance.now(),h=this.chooseWorkerNode(),u={name:t??l,data:e??{},transferList:s,timestamp:a,workerId:this.getWorkerInfo(h).id,taskId:r.randomUUID()};this.promiseResponseMap.set(u.taskId,{resolve:o,reject:n,workerNodeKey:h}),!1===this.opts.enableTasksQueue||!0===this.opts.enableTasksQueue&&this.workerNodes[h].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency?this.executeTask(h,u):this.enqueueTask(h,u),this.checkAndEmitEvents()}))}async destroy(){await Promise.all(this.workerNodes.map((async(e,t)=>{await this.destroyWorkerNode(t)})))}async sendKillMessageToWorker(e,t){await new Promise(((s,r)=>{this.registerWorkerMessageListener(e,(e=>{"success"===e.kill?s():"failure"===e.kill&&r(new Error(`Worker ${t} kill message handling failed`))})),this.sendToWorker(e,{kill:!0,workerId:t})}))}setupHook(){}beforeTaskExecutionHook(e,t){const s=this.workerNodes[e].usage;++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t);const r=this.workerNodes[e].getTaskWorkerUsage(t.name);++r.tasks.executing,this.updateWaitTimeWorkerUsage(r,t)}afterTaskExecutionHook(e,t){const s=this.workerNodes[e].usage;this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t);const r=this.workerNodes[e].getTaskWorkerUsage(t.taskPerformance?.name??l);this.updateTaskStatisticsWorkerUsage(r,t),this.updateRunTimeWorkerUsage(r,t),this.updateEluWorkerUsage(r,t)}updateTaskStatisticsWorkerUsage(e,t){const s=e.tasks;--s.executing,null==t.taskError?++s.executed:++s.failed}updateRunTimeWorkerUsage(e,t){N(e.runTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime,t.taskPerformance?.runTime??0,e.tasks.executed)}updateWaitTimeWorkerUsage(e,t){const s=i.performance.now(),r=s-(t.timestamp??s);N(e.waitTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime,r,e.tasks.executed)}updateEluWorkerUsage(e,t){const s=this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu;N(e.elu.active,s,t.taskPerformance?.elu?.active??0,e.tasks.executed),N(e.elu.idle,s,t.taskPerformance?.elu?.idle??0,e.tasks.executed),s.aggregate&&null!=t.taskPerformance?.elu&&(null!=e.elu.utilization?e.elu.utilization=(e.elu.utilization+t.taskPerformance.elu.utilization)/2:e.elu.utilization=t.taskPerformance.elu.utilization)}chooseWorkerNode(){if(this.shallCreateDynamicWorker()){const e=this.createAndSetupDynamicWorkerNode();if(this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker)return e}return this.workerChoiceStrategyContext.execute()}shallCreateDynamicWorker(){return this.type===k.dynamic&&!this.full&&this.internalBusy()}createAndSetupWorkerNode(){const e=this.createWorker();e.on("message",this.opts.messageHandler??m),e.on("error",this.opts.errorHandler??m),e.on("error",(t=>{const s=this.getWorkerNodeKeyByWorker(e),r=this.getWorkerInfo(s);r.ready=!1,this.workerNodes[s].closeChannel(),this.emitter?.emit(d.error,t),!0!==this.opts.restartWorkerOnError||this.starting||(r.dynamic?this.createAndSetupDynamicWorkerNode():this.createAndSetupWorkerNode()),!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(s)})),e.on("online",this.opts.onlineHandler??m),e.on("exit",this.opts.exitHandler??m),e.once("exit",(()=>{this.removeWorkerNode(e)}));const t=this.addWorkerNode(e);return this.afterWorkerNodeSetup(t),t}createAndSetupDynamicWorkerNode(){const e=this.createAndSetupWorkerNode();this.registerWorkerMessageListener(e,(e=>{const t=this.getWorkerNodeKeyByWorkerId(e.workerId),s=this.workerNodes[t].usage;(T(x.HARD,e.kill)||T(x.SOFT,e.kill)&&(!1===this.opts.enableTasksQueue&&0===s.tasks.executing||!0===this.opts.enableTasksQueue&&0===s.tasks.executing&&0===this.tasksQueueSize(t)))&&this.destroyWorkerNode(t).catch((e=>{this.emitter?.emit(d.error,e)}))}));const t=this.getWorkerInfo(e);return this.sendToWorker(e,{checkActive:!0,workerId:t.id}),t.dynamic=!0,this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker&&(t.ready=!0),e}afterWorkerNodeSetup(e){this.registerWorkerMessageListener(e,this.workerListener()),this.sendStartupMessageToWorker(e),this.sendStatisticsMessageToWorker(e)}sendStatisticsMessageToWorker(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate},workerId:this.getWorkerInfo(e).id})}redistributeQueuedTasks(e){for(;this.tasksQueueSize(e)>0;){let t=e,s=1/0,r=!1;for(const[i,o]of this.workerNodes.entries()){const n=this.getWorkerInfo(i);if(i!==e&&n.ready&&0===o.usage.tasks.queued){this.workerNodes[i].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&(r=!0),t=i;break}i!==e&&n.ready&&o.usage.tasks.queued<s&&(s=o.usage.tasks.queued,t=i)}r?this.executeTask(t,this.dequeueTask(e)):this.enqueueTask(t,this.dequeueTask(e))}}workerListener(){return e=>{this.checkMessageWorkerId(e),null!=e.ready?this.handleWorkerReadyResponse(e):null!=e.taskId?this.handleTaskExecutionResponse(e):null!=e.taskFunctions&&(this.taskFunctions=e.taskFunctions)}}handleWorkerReadyResponse(e){this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId)).ready=e.ready,null!=this.emitter&&this.ready&&this.emitter.emit(d.ready,this.info)}handleTaskExecutionResponse(e){const t=this.promiseResponseMap.get(e.taskId);if(null!=t){null!=e.taskError?(this.emitter?.emit(d.taskError,e.taskError),t.reject(e.taskError.message)):t.resolve(e.data);const s=t.workerNodeKey;this.afterTaskExecutionHook(s,e),this.promiseResponseMap.delete(e.taskId),!0===this.opts.enableTasksQueue&&this.tasksQueueSize(s)>0&&this.workerNodes[s].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&this.executeTask(s,this.dequeueTask(s)),this.workerChoiceStrategyContext.update(s)}}checkAndEmitEvents(){null!=this.emitter&&(this.busy&&this.emitter.emit(d.busy,this.info),this.type===k.dynamic&&this.full&&this.emitter.emit(d.full,this.info))}getWorkerInfo(e){return this.workerNodes[e].info}addWorkerNode(e){const t=new A(e,this.worker);this.starting&&(t.info.ready=!0),this.workerNodes.push(t);const s=this.getWorkerNodeKeyByWorker(e);if(-1===s)throw new Error("Worker node not found");return s}removeWorkerNode(e){const t=this.getWorkerNodeKeyByWorker(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategyContext.remove(t))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(e,t,t.transferList)}enqueueTask(e,t){return this.workerNodes[e].enqueueTask(t)}dequeueTask(e){return this.workerNodes[e].dequeueTask()}tasksQueueSize(e){return this.workerNodes[e].tasksQueueSize()}flushTasksQueue(e){for(;this.tasksQueueSize(e)>0;)this.executeTask(e,this.dequeueTask(e));this.workerNodes[e].clearTasksQueue()}flushTasksQueues(){for(const[e]of this.workerNodes.entries())this.flushTasksQueue(e)}}class U extends P{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}setupHook(){s.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return s.isPrimary}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e].worker,s=new Promise((e=>{t.on("exit",(()=>{e()}))}));t.on("disconnect",(()=>{t.kill()})),await this.sendKillMessageToWorker(e,t.id),t.disconnect(),await s}sendToWorker(e,t){this.workerNodes[e].worker.send(t)}sendStartupMessageToWorker(e){this.sendToWorker(e,{ready:!1,workerId:this.workerNodes[e].worker.id})}registerWorkerMessageListener(e,t){this.workerNodes[e].worker.on("message",t)}createWorker(){return s.fork(this.opts.env)}get type(){return k.fixed}get worker(){return F.cluster}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}class D extends P{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}isMain(){return t.isMainThread}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e],s=t.worker,r=new Promise((e=>{s.on("exit",(()=>{e()}))}));await this.sendKillMessageToWorker(e,s.threadId),t.closeChannel(),await s.terminate(),await r}sendToWorker(e,t,s){this.getWorkerInfo(e).messageChannel.port1.postMessage(t,s)}sendStartupMessageToWorker(e){const t=this.workerNodes[e].worker,s=this.getWorkerInfo(e).messageChannel.port2;t.postMessage({ready:!1,workerId:t.threadId,port:s},[s])}registerWorkerMessageListener(e,t){this.getWorkerInfo(e).messageChannel.port1.on("message",t)}createWorker(){return new t.Worker(this.filePath,{env:t.SHARE_ENV,...this.opts.workerOptions})}get type(){return k.fixed}get worker(){return F.thread}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}const L=6e4,_=x.SOFT;class B extends a.AsyncResource{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,s,r,i={killBehavior:_,maxInactiveTime:L,killHandler:m}){super(e),this.isMain=t,this.mainWorker=s,this.opts=i,this.checkWorkerOptions(this.opts),this.checkTaskFunctions(r),this.isMain||this.getMainWorker()?.on("message",this.handleReadyMessage.bind(this))}checkWorkerOptions(e){this.opts.killBehavior=e.killBehavior??_,this.opts.maxInactiveTime=e.maxInactiveTime??L,delete this.opts.async,this.opts.killHandler=e.killHandler??m}checkTaskFunctions(e){if(null==e)throw new Error("taskFunctions parameter is mandatory");if(this.taskFunctions=new Map,"function"==typeof e){const t=e.bind(this);this.taskFunctions.set(l,t),this.taskFunctions.set("string"==typeof e.name&&e.name.trim().length>0?e.name:"fn1",t)}else{if(!f(e))throw new TypeError("taskFunctions parameter is not a function or a plain object");{let t=!0;for(const[s,r]of Object.entries(e)){if("string"!=typeof s)throw new TypeError("A taskFunctions parameter object key is not a string");if("string"==typeof s&&0===s.trim().length)throw new TypeError("A taskFunctions parameter object key an empty string");if("function"!=typeof r)throw new TypeError("A taskFunctions parameter object value is not a function");const e=r.bind(this);t&&(this.taskFunctions.set(l,e),t=!1),this.taskFunctions.set(s,e)}if(t)throw new Error("taskFunctions parameter object is empty")}}}hasTaskFunction(e){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");return this.taskFunctions.has(e)}addTaskFunction(e,t){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");if(e===l)throw new Error("Cannot add a task function with the default reserved name");if("function"!=typeof t)throw new TypeError("fn parameter is not a function");try{const s=t.bind(this);return this.taskFunctions.get(e)===this.taskFunctions.get(l)&&this.taskFunctions.set(l,s),this.taskFunctions.set(e,s),this.sendTaskFunctionsListToMainWorker(),!0}catch{return!1}}removeTaskFunction(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");if(e===l)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(l))throw new Error("Cannot remove the task function used as the default task function");const t=this.taskFunctions.delete(e);return this.sendTaskFunctionsListToMainWorker(),t}listTaskFunctions(){return[...this.taskFunctions.keys()]}setDefaultTaskFunction(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");if(e===l)throw new Error("Cannot set the default task function reserved name as the default task function");if(!this.taskFunctions.has(e))throw new Error("Cannot set the default task function to a non-existing task function");try{return this.taskFunctions.set(l,this.taskFunctions.get(e)),!0}catch{return!1}}messageListener(e){if(this.isMain)throw new Error("Cannot handle message to worker in main worker");if(null!=e.workerId&&e.workerId!==this.id)throw new Error(`Message worker id ${e.workerId} does not match the worker id ${this.id}`);e.workerId===this.id&&(null!=e.statistics?this.statistics=e.statistics:null!=e.checkActive?e.checkActive?this.startCheckActive():this.stopCheckActive():null!=e.taskId&&null!=e.data?this.run(e):!0===e.kill&&this.handleKillMessage(e))}handleKillMessage(e){if(this.stopCheckActive(),W(this.opts.killHandler))(this.opts.killHandler?.()).then((()=>(this.sendToMainWorker({kill:"success",workerId:this.id}),null))).catch((()=>{this.sendToMainWorker({kill:"failure",workerId:this.id})})).finally((()=>{this.emitDestroy()})).catch(m);else try{this.opts.killHandler?.(),this.sendToMainWorker({kill:"success",workerId:this.id})}catch{this.sendToMainWorker({kill:"failure",workerId:this.id})}finally{this.emitDestroy()}}startCheckActive(){this.lastTaskTimestamp=i.performance.now(),this.activeInterval=setInterval(this.checkActive.bind(this),(this.opts.maxInactiveTime??L)/2)}stopCheckActive(){null!=this.activeInterval&&(clearInterval(this.activeInterval),delete this.activeInterval)}checkActive(){i.performance.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??L)&&this.sendToMainWorker({kill:this.opts.killBehavior,workerId:this.id})}getMainWorker(){if(null==this.mainWorker)throw new Error("Main worker not set");return this.mainWorker}sendTaskFunctionsListToMainWorker(){this.sendToMainWorker({taskFunctions:this.listTaskFunctions(),workerId:this.id})}handleError(e){return e instanceof Error?e.message:e}run(e){const t=this.getTaskFunction(e.name);W(t)?this.runInAsyncScope(this.runAsync.bind(this),this,t,e):this.runInAsyncScope(this.runSync.bind(this),this,t,e)}runSync(e,t){try{let s=this.beginTaskPerformance(t.name);const r=e(t.data);s=this.endTaskPerformance(s),this.sendToMainWorker({data:r,taskPerformance:s,workerId:this.id,taskId:t.taskId})}catch(e){const s=this.handleError(e);this.sendToMainWorker({taskError:{name:t.name??l,message:s,data:t.data},workerId:this.id,taskId:t.taskId})}finally{this.updateLastTaskTimestamp()}}runAsync(e,t){let s=this.beginTaskPerformance(t.name);e(t.data).then((e=>(s=this.endTaskPerformance(s),this.sendToMainWorker({data:e,taskPerformance:s,workerId:this.id,taskId:t.taskId}),null))).catch((e=>{const s=this.handleError(e);this.sendToMainWorker({taskError:{name:t.name??l,message:s,data:t.data},workerId:this.id,taskId:t.taskId})})).finally((()=>{this.updateLastTaskTimestamp()})).catch(m)}getTaskFunction(e){e=e??l;const t=this.taskFunctions.get(e);if(null==t)throw new Error(`Task function '${e}' not found`);return t}beginTaskPerformance(e){return this.checkStatistics(),{name:e??l,timestamp:i.performance.now(),...this.statistics.elu&&{elu:i.performance.eventLoopUtilization()}}}endTaskPerformance(e){return this.checkStatistics(),{...e,...this.statistics.runTime&&{runTime:i.performance.now()-e.timestamp},...this.statistics.elu&&{elu:i.performance.eventLoopUtilization(e.elu)}}}checkStatistics(){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set")}updateLastTaskTimestamp(){null!=this.activeInterval&&(this.lastTaskTimestamp=i.performance.now())}}exports.ClusterWorker=class extends B{constructor(e,t={}){super("worker-cluster-pool:poolifier",s.isPrimary,s.worker,e,t)}handleReadyMessage(e){e.workerId===this.id&&null!=e.ready&&(this.getMainWorker()?.on("message",this.messageListener.bind(this)),this.sendTaskFunctionsListToMainWorker(),this.sendToMainWorker({ready:!0,workerId:this.id}))}get id(){return this.getMainWorker().id}sendToMainWorker(e){this.getMainWorker().send(e)}},exports.DynamicClusterPool=class extends U{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return k.dynamic}get maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}},exports.DynamicThreadPool=class extends D{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return k.dynamic}get maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}},exports.FixedClusterPool=U,exports.FixedThreadPool=D,exports.KillBehaviors=x,exports.Measurements=E,exports.PoolEvents=d,exports.PoolTypes=k,exports.ThreadWorker=class extends B{port;constructor(e,s={}){super("worker-thread-pool:poolifier",t.isMainThread,t.parentPort,e,s)}handleReadyMessage(e){e.workerId===this.id&&null!=e.ready&&null!=e.port&&(this.port=e.port,this.port.on("message",this.messageListener.bind(this)),this.sendTaskFunctionsListToMainWorker(),this.sendToMainWorker({ready:!0,workerId:this.id}))}handleKillMessage(e){super.handleKillMessage(e),this.port?.unref(),this.port?.close()}get id(){return t.threadId}sendToMainWorker(e){this.port.postMessage(e)}handleError(e){return e}},exports.WorkerChoiceStrategies=S,exports.WorkerTypes=F,exports.availableParallelism=()=>{let e=1;try{e=u.availableParallelism()}catch{const t=u.cpus();Array.isArray(t)&&t.length>0&&(e=t.length)}return e};
|
package/lib/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{EventEmitter as e}from"node:events";import{MessageChannel as t,isMainThread as s,Worker as r,SHARE_ENV as i,parentPort as o,threadId as n}from"node:worker_threads";import a from"node:cluster";import{randomUUID as h}from"node:crypto";import{performance as u}from"node:perf_hooks";import{existsSync as k}from"node:fs";import*as c from"node:os";import{cpus as d}from"node:os";import{AsyncResource as l}from"node:async_hooks";const m=Object.freeze({fixed:"fixed",dynamic:"dynamic"});class g extends e{}const p=Object.freeze({full:"full",ready:"ready",busy:"busy",error:"error",taskError:"taskError"}),w="default",y=Object.freeze((()=>{})),f={runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},T={aggregate:!1,average:!1,median:!1},W=()=>{let e=1;try{e=c.availableParallelism()}catch{const t=c.cpus();Array.isArray(t)&&t.length>0&&(e=t.length)}return e},N=e=>{if(Array.isArray(e)&&0===e.length)return 0;if(Array.isArray(e)&&1===e.length)return e[0];const t=e.slice().sort(((e,t)=>e-t));return(t[t.length-1>>1]+t[t.length>>1])/2},x=(e,t=2)=>{const s=Math.pow(10,t);return Math.round(e*s*(1+Number.EPSILON))/s},S=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),E=(e,t,s,r)=>{t.aggregate&&(e.aggregate=(e.aggregate??0)+s,e.minimum=Math.min(s,e.minimum??1/0),e.maximum=Math.max(s,e.maximum??-1/0),t.average&&0!==r&&(e.average=e.aggregate/r),t.median&&null!=s&&(e.history.push(s),e.median=N(e.history)))},I=Object.freeze({SOFT:"SOFT",HARD:"HARD"}),b=Object.freeze({ROUND_ROBIN:"ROUND_ROBIN",LEAST_USED:"LEAST_USED",LEAST_BUSY:"LEAST_BUSY",LEAST_ELU:"LEAST_ELU",FAIR_SHARE:"FAIR_SHARE",WEIGHTED_ROUND_ROBIN:"WEIGHTED_ROUND_ROBIN",INTERLEAVED_WEIGHTED_ROUND_ROBIN:"INTERLEAVED_WEIGHTED_ROUND_ROBIN"}),R=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"});class C{pool;opts;nextWorkerNodeKey=0;strategyPolicy={useDynamicWorker:!1};taskStatisticsRequirements={runTime:T,waitTime:T,elu:T};constructor(e,t=f){this.pool=e,this.opts=t,this.choose=this.choose.bind(this)}setTaskStatisticsRequirements(e){this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.runTime,e.runTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.waitTime,e.waitTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.elu,e.elu?.median)}toggleMedianMeasurementStatisticsRequirements(e,t){e.average&&t&&(e.average=!1,e.median=t),e.median&&!t&&(e.average=!0,e.median=t)}setOptions(e){this.opts=e??f,this.setTaskStatisticsRequirements(this.opts)}isWorkerNodeReady(e){return this.pool.workerNodes[e].info.ready}getWorkerTaskRunTime(e){return this.taskStatisticsRequirements.runTime.median?this.pool.workerNodes[e].usage.runTime?.median??0:this.pool.workerNodes[e].usage.runTime?.average??0}getWorkerTaskWaitTime(e){return this.taskStatisticsRequirements.waitTime.median?this.pool.workerNodes[e].usage.waitTime?.median??0:this.pool.workerNodes[e].usage.waitTime?.average??0}getWorkerTaskElu(e){return this.taskStatisticsRequirements.elu.median?this.pool.workerNodes[e].usage.elu.active?.median??0:this.pool.workerNodes[e].usage.elu.active?.average??0}computeDefaultWorkerWeight(){let e=0;for(const t of d()){const s=t.speed.toString().length-1;e+=1/(t.speed/Math.pow(10,s))*Math.pow(10,s)}return Math.round(e/d().length)}}class v extends C{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:T,elu:{aggregate:!0,average:!0,median:!1}};workersVirtualTaskEndTimestamp=[];constructor(e,t=f){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.workersVirtualTaskEndTimestamp=[],!0}update(e){return this.computeWorkerVirtualTaskEndTimestamp(e),!0}choose(){return this.fairShareNextWorkerNodeKey()}remove(e){return this.workersVirtualTaskEndTimestamp.splice(e,1),!0}fairShareNextWorkerNodeKey(){let e=1/0;for(const[t]of this.pool.workerNodes.entries()){null==this.workersVirtualTaskEndTimestamp[t]&&this.computeWorkerVirtualTaskEndTimestamp(t);const s=this.workersVirtualTaskEndTimestamp[t];this.isWorkerNodeReady(t)&&s<e&&(e=s,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}computeWorkerVirtualTaskEndTimestamp(e){this.workersVirtualTaskEndTimestamp[e]=this.getWorkerVirtualTaskEndTimestamp(e,this.getWorkerVirtualTaskStartTimestamp(e))}getWorkerVirtualTaskEndTimestamp(e,t){return t+(this.opts.measurement===R.elu?this.getWorkerTaskElu(e):this.getWorkerTaskRunTime(e))}getWorkerVirtualTaskStartTimestamp(e){return Math.max(performance.now(),this.workersVirtualTaskEndTimestamp[e]??-1/0)}}class O extends C{strategyPolicy={useDynamicWorker:!0};roundId=0;roundWeights;defaultWorkerWeight;constructor(e,t=f){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight(),this.roundWeights=this.getRoundWeights()}reset(){return this.nextWorkerNodeKey=0,this.roundId=0,!0}update(){return!0}choose(){let e,t;for(let s=this.roundId;s<this.roundWeights.length;s++)for(let r=this.nextWorkerNodeKey;r<this.pool.workerNodes.length;r++){const i=this.opts.weights?.[r]??this.defaultWorkerWeight;if(this.isWorkerNodeReady(r)&&i>=this.roundWeights[s]){e=s,t=r;break}}this.roundId=e??0,this.nextWorkerNodeKey=t??0;const s=this.nextWorkerNodeKey;return this.nextWorkerNodeKey===this.pool.workerNodes.length-1?(this.nextWorkerNodeKey=0,this.roundId=this.roundId===this.roundWeights.length-1?0:this.roundId+1):this.nextWorkerNodeKey=this.nextWorkerNodeKey+1,s}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1,this.roundId=this.roundId===this.roundWeights.length-1?0:this.roundId+1)),!0}setOptions(e){super.setOptions(e),this.roundWeights=this.getRoundWeights()}getRoundWeights(){return null==this.opts.weights?[this.defaultWorkerWeight]:[...new Set(Object.values(this.opts.weights).slice().sort(((e,t)=>e-t)))]}}class z extends C{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:T};constructor(e,t=f){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.leastBusyNextWorkerNodeKey()}remove(){return!0}leastBusyNextWorkerNodeKey(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=(s.usage.runTime?.aggregate??0)+(s.usage.waitTime?.aggregate??0);if(this.isWorkerNodeReady(t)&&0===r){this.nextWorkerNodeKey=t;break}this.isWorkerNodeReady(t)&&r<e&&(e=r,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}}class M extends C{constructor(e,t=f){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.leastUsedNextWorkerNodeKey()}remove(){return!0}leastUsedNextWorkerNodeKey(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=s.usage.tasks,i=r.executed+r.executing+r.queued;if(this.isWorkerNodeReady(t)&&0===i){this.nextWorkerNodeKey=t;break}this.isWorkerNodeReady(t)&&i<e&&(e=i,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}}class K extends C{taskStatisticsRequirements={runTime:T,waitTime:T,elu:{aggregate:!0,average:!1,median:!1}};constructor(e,t=f){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.leastEluNextWorkerNodeKey()}remove(){return!0}leastEluNextWorkerNodeKey(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=s.usage,i=r.elu?.active?.aggregate??0;if(this.isWorkerNodeReady(t)&&0===i){this.nextWorkerNodeKey=t;break}this.isWorkerNodeReady(t)&&i<e&&(e=i,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}}class q extends C{strategyPolicy={useDynamicWorker:!0};constructor(e,t=f){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.nextWorkerNodeKey=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;do{this.roundRobinNextWorkerNodeKey()}while(!this.isWorkerNodeReady(this.nextWorkerNodeKey));return e}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1)),!0}roundRobinNextWorkerNodeKey(){return this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:this.nextWorkerNodeKey+1,this.nextWorkerNodeKey}}class Q extends C{strategyPolicy={useDynamicWorker:!0};taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:T,elu:T};defaultWorkerWeight;workerVirtualTaskRunTime=0;constructor(e,t=f){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight()}reset(){return this.nextWorkerNodeKey=0,this.workerVirtualTaskRunTime=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;do{this.weightedRoundRobinNextWorkerNodeKey()}while(!this.isWorkerNodeReady(this.nextWorkerNodeKey));return e}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1),this.workerVirtualTaskRunTime=0),!0}weightedRoundRobinNextWorkerNodeKey(){const e=this.workerVirtualTaskRunTime;return e<(this.opts.weights?.[this.nextWorkerNodeKey]??this.defaultWorkerWeight)?this.workerVirtualTaskRunTime=e+this.getWorkerTaskRunTime(this.nextWorkerNodeKey):(this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:this.nextWorkerNodeKey+1,this.workerVirtualTaskRunTime=0),this.nextWorkerNodeKey}}class A{workerChoiceStrategy;workerChoiceStrategies;constructor(e,t=b.ROUND_ROBIN,s=f){this.workerChoiceStrategy=t,this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[b.ROUND_ROBIN,new(q.bind(this))(e,s)],[b.LEAST_USED,new(M.bind(this))(e,s)],[b.LEAST_BUSY,new(z.bind(this))(e,s)],[b.LEAST_ELU,new(K.bind(this))(e,s)],[b.FAIR_SHARE,new(v.bind(this))(e,s)],[b.WEIGHTED_ROUND_ROBIN,new(Q.bind(this))(e,s)],[b.INTERLEAVED_WEIGHTED_ROUND_ROBIN,new(O.bind(this))(e,s)]])}getStrategyPolicy(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).strategyPolicy}getTaskStatisticsRequirements(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).taskStatisticsRequirements}setWorkerChoiceStrategy(e){this.workerChoiceStrategy!==e&&(this.workerChoiceStrategy=e),this.workerChoiceStrategies.get(this.workerChoiceStrategy)?.reset()}update(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).update(e)}execute(){const e=this.workerChoiceStrategies.get(this.workerChoiceStrategy).choose();if(null==e)throw new TypeError("Worker node key chosen is null or undefined");return e}remove(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).remove(e)}setOptions(e){for(const t of this.workerChoiceStrategies.values())t.setOptions(e)}}class U extends Array{size;constructor(e=1024,...t){super(),this.checkSize(e),this.size=e,arguments.length>1&&this.push(...t)}push(...e){const t=super.push(...e);return t>this.size&&super.splice(0,t-this.size),this.length}unshift(...e){return super.unshift(...e)>this.size&&super.splice(this.size,e.length),this.length}concat(...e){const t=super.concat(e);return t.size=this.size,t.length>t.size&&t.splice(0,t.length-t.size),t}splice(e,t,...s){let r=[];if(arguments.length>=3&&null!=t){if(r=super.splice(e,t,...s),this.length>this.size){const e=super.splice(0,this.length-this.size);r=new U(r.length+e.length,...r,...e)}}else r=2===arguments.length?super.splice(e,t):super.splice(e);return r}resize(e){if(this.checkSize(e),0===e)this.length=0;else if(e<this.size)for(let t=e;t<this.size;t++)super.pop();this.size=e}empty(){return 0===this.length}full(){return this.length===this.size}checkSize(e){if(!Number.isSafeInteger(e))throw new TypeError(`Invalid circular array size: ${e} is not a safe integer`);if(e<0)throw new RangeError(`Invalid circular array size: ${e} < 0`)}}class P{items;offset;size;maxSize;constructor(){this.clear()}enqueue(e){return this.items.push(e),++this.size,this.size>this.maxSize&&(this.maxSize=this.size),this.size}dequeue(){if(this.size<=0)return;const e=this.items[this.offset];return 2*++this.offset>=this.items.length&&(this.items=this.items.slice(this.offset),this.offset=0),--this.size,e}peek(){if(!(this.size<=0))return this.items[this.offset]}clear(){this.items=[],this.offset=0,this.size=0,this.maxSize=0}[Symbol.iterator](){const e=this.items;let t=this.offset;return{next:()=>{if(t>=e.length)return{value:void 0,done:!0};const s=e[t];return++t,{value:s,done:!1}}}}}const D=Object.freeze({thread:"thread",cluster:"cluster"});class F{worker;info;usage;tasksUsage;tasksQueue;constructor(e,t){this.worker=e,this.info=this.initWorkerInfo(e,t),this.usage=this.initWorkerUsage(),this.tasksUsage=new Map,this.tasksQueue=new P}tasksQueueSize(){return this.tasksQueue.size}tasksQueueMaxSize(){return this.tasksQueue.maxSize}enqueueTask(e){return this.tasksQueue.enqueue(e)}dequeueTask(){return this.tasksQueue.dequeue()}clearTasksQueue(){this.tasksQueue.clear()}resetUsage(){this.usage=this.initWorkerUsage(),this.tasksUsage.clear()}closeChannel(){null!=this.info.messageChannel&&(this.info.messageChannel?.port1.unref(),this.info.messageChannel?.port2.unref(),this.info.messageChannel?.port1.close(),this.info.messageChannel?.port2.close(),delete this.info.messageChannel)}getTaskWorkerUsage(e){return this.tasksUsage.has(e)||this.tasksUsage.set(e,this.initTaskWorkerUsage(e)),this.tasksUsage.get(e)}initWorkerInfo(e,s){return{id:this.getWorkerId(e,s),type:s,dynamic:!1,ready:!1,...s===D.thread&&{messageChannel:new t}}}initWorkerUsage(){const e=()=>this.tasksQueueSize(),t=()=>this.tasksQueueMaxSize();return{tasks:{executed:0,executing:0,get queued(){return e()},get maxQueued(){return t()},failed:0},runTime:{history:new U},waitTime:{history:new U},elu:{idle:{history:new U},active:{history:new U}}}}initTaskWorkerUsage(e){const t=()=>{let t=0;for(const s of this.tasksQueue)s.name===e&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},failed:0},runTime:{history:new U},waitTime:{history:new U},elu:{idle:{history:new U},active:{history:new U}}}}getWorkerId(e,t){return t===D.thread?e.threadId:t===D.cluster?e.id:void 0}}class _{numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;starting;startTimestamp;constructor(e,t,s){if(this.numberOfWorkers=e,this.filePath=t,this.opts=s,!this.isMain())throw new Error("Cannot start a pool from a worker!");this.checkNumberOfWorkers(this.numberOfWorkers),this.checkFilePath(this.filePath),this.checkPoolOptions(this.opts),this.chooseWorkerNode=this.chooseWorkerNode.bind(this),this.executeTask=this.executeTask.bind(this),this.enqueueTask=this.enqueueTask.bind(this),this.dequeueTask=this.dequeueTask.bind(this),this.checkAndEmitEvents=this.checkAndEmitEvents.bind(this),!0===this.opts.enableEvents&&(this.emitter=new g),this.workerChoiceStrategyContext=new A(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook(),this.starting=!0,this.startPool(),this.starting=!1,this.startTimestamp=u.now()}checkFilePath(e){if(null==e||"string"!=typeof e||"string"==typeof e&&0===e.trim().length)throw new Error("Please specify a file with a worker implementation");if(!k(e))throw new Error(`Cannot find the worker file '${e}'`)}checkNumberOfWorkers(e){if(null==e)throw new Error("Cannot instantiate a pool without specifying the number of workers");if(!Number.isSafeInteger(e))throw new TypeError("Cannot instantiate a pool with a non safe integer number of workers");if(e<0)throw new RangeError("Cannot instantiate a pool with a negative number of workers");if(this.type===m.fixed&&0===e)throw new RangeError("Cannot instantiate a fixed pool with zero worker")}checkDynamicPoolSize(e,t){if(this.type===m.dynamic){if(null==t)throw new Error("Cannot instantiate a dynamic pool without specifying the maximum pool size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot instantiate a dynamic pool with a non safe integer maximum pool size");if(e>t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size");if(0===t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size equal to zero");if(e===t)throw new RangeError("Cannot instantiate a dynamic pool with a minimum pool size equal to the maximum pool size. Use a fixed pool instead")}}checkPoolOptions(e){if(!S(e))throw new TypeError("Invalid pool options: must be a plain object");this.opts.workerChoiceStrategy=e.workerChoiceStrategy??b.ROUND_ROBIN,this.checkValidWorkerChoiceStrategy(this.opts.workerChoiceStrategy),this.opts.workerChoiceStrategyOptions=e.workerChoiceStrategyOptions??f,this.checkValidWorkerChoiceStrategyOptions(this.opts.workerChoiceStrategyOptions),this.opts.restartWorkerOnError=e.restartWorkerOnError??!0,this.opts.enableEvents=e.enableEvents??!0,this.opts.enableTasksQueue=e.enableTasksQueue??!1,this.opts.enableTasksQueue&&(this.checkValidTasksQueueOptions(e.tasksQueueOptions),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e.tasksQueueOptions))}checkValidWorkerChoiceStrategy(e){if(!Object.values(b).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)}checkValidWorkerChoiceStrategyOptions(e){if(!S(e))throw new TypeError("Invalid worker choice strategy options: must be a plain object");if(null!=e.weights&&Object.keys(e.weights).length!==this.maxSize)throw new Error("Invalid worker choice strategy options: must have a weight for each worker node");if(null!=e.measurement&&!Object.values(R).includes(e.measurement))throw new Error(`Invalid worker choice strategy options: invalid measurement '${e.measurement}'`)}checkValidTasksQueueOptions(e){if(null!=e&&!S(e))throw new TypeError("Invalid tasks queue options: must be a plain object");if(null!=e?.concurrency&&!Number.isSafeInteger(e.concurrency))throw new TypeError("Invalid worker tasks concurrency: must be an integer");if(null!=e?.concurrency&&e.concurrency<=0)throw new Error(`Invalid worker tasks concurrency '${e.concurrency}'`)}startPool(){for(;this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.numberOfWorkers;)this.createAndSetupWorkerNode()}get info(){return{version:"2.6.24",type:this.type,worker:this.worker,ready:this.ready,strategy:this.opts.workerChoiceStrategy,minSize:this.minSize,maxSize:this.maxSize,...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{utilization:x(this.utilization)},workerNodes:this.workerNodes.length,idleWorkerNodes:this.workerNodes.reduce(((e,t)=>0===t.usage.tasks.executing?e+1:e),0),busyWorkerNodes:this.workerNodes.reduce(((e,t)=>t.usage.tasks.executing>0?e+1:e),0),executedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executed),0),executingTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executing),0),...!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)},failedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.failed),0),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&{runTime:{minimum:x(Math.min(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:x(Math.max(...this.workerNodes.map((e=>e.usage.runTime?.maximum??-1/0)))),average:x(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)/this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.executed??0)),0)),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&{median:x(N(this.workerNodes.map((e=>e.usage.runTime?.median??0))))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:x(Math.min(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:x(Math.max(...this.workerNodes.map((e=>e.usage.waitTime?.maximum??-1/0)))),average:x(this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0)/this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.executed??0)),0)),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&{median:x(N(this.workerNodes.map((e=>e.usage.waitTime?.median??0))))}}}}}get ready(){return this.workerNodes.reduce(((e,t)=>!t.info.dynamic&&t.info.ready?e+1:e),0)>=this.minSize}get utilization(){const e=(u.now()-this.startTimestamp)*this.maxSize;return(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)+this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0))/e}checkMessageWorkerId(e){if(null!=e.workerId&&-1===this.getWorkerNodeKeyByWorkerId(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKeyByWorker(e){return this.workerNodes.findIndex((t=>t.worker===e))}getWorkerNodeKeyByWorkerId(e){return this.workerNodes.findIndex((t=>t.info.id===e))}setWorkerChoiceStrategy(e,t){this.checkValidWorkerChoiceStrategy(e),this.opts.workerChoiceStrategy=e,this.workerChoiceStrategyContext.setWorkerChoiceStrategy(this.opts.workerChoiceStrategy),null!=t&&this.setWorkerChoiceStrategyOptions(t);for(const[e,t]of this.workerNodes.entries())t.resetUsage(),this.sendWorkerStatisticsMessageToWorker(e)}setWorkerChoiceStrategyOptions(e){this.checkValidWorkerChoiceStrategyOptions(e),this.opts.workerChoiceStrategyOptions=e,this.workerChoiceStrategyContext.setOptions(this.opts.workerChoiceStrategyOptions)}enableTasksQueue(e,t){!0!==this.opts.enableTasksQueue||e||this.flushTasksQueues(),this.opts.enableTasksQueue=e,this.setTasksQueueOptions(t)}setTasksQueueOptions(e){!0===this.opts.enableTasksQueue?(this.checkValidTasksQueueOptions(e),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e)):null!=this.opts.tasksQueueOptions&&delete this.opts.tasksQueueOptions}buildTasksQueueOptions(e){return{concurrency:e?.concurrency??1}}get full(){return this.workerNodes.length>=this.maxSize}internalBusy(){return!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))}async execute(e,t,s){return await new Promise(((r,i)=>{null!=t&&"string"!=typeof t&&i(new TypeError("name argument must be a string")),null==s||Array.isArray(s)||i(new TypeError("transferList argument must be an array"));const o=u.now(),n=this.chooseWorkerNode(),a={name:t??w,data:e??{},transferList:s,timestamp:o,workerId:this.getWorkerInfo(n).id,taskId:h()};this.promiseResponseMap.set(a.taskId,{resolve:r,reject:i,workerNodeKey:n}),!1===this.opts.enableTasksQueue||!0===this.opts.enableTasksQueue&&this.workerNodes[n].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency?this.executeTask(n,a):this.enqueueTask(n,a),this.checkAndEmitEvents()}))}async destroy(){await Promise.all(this.workerNodes.map((async(e,t)=>{await this.destroyWorkerNode(t)})))}setupHook(){}beforeTaskExecutionHook(e,t){const s=this.workerNodes[e].usage;++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t);const r=this.workerNodes[e].getTaskWorkerUsage(t.name);++r.tasks.executing,this.updateWaitTimeWorkerUsage(r,t)}afterTaskExecutionHook(e,t){const s=this.workerNodes[e].usage;this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t);const r=this.workerNodes[e].getTaskWorkerUsage(t.taskPerformance?.name??w);this.updateTaskStatisticsWorkerUsage(r,t),this.updateRunTimeWorkerUsage(r,t),this.updateEluWorkerUsage(r,t)}updateTaskStatisticsWorkerUsage(e,t){const s=e.tasks;--s.executing,null==t.taskError?++s.executed:++s.failed}updateRunTimeWorkerUsage(e,t){E(e.runTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime,t.taskPerformance?.runTime??0,e.tasks.executed)}updateWaitTimeWorkerUsage(e,t){const s=u.now(),r=s-(t.timestamp??s);E(e.waitTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime,r,e.tasks.executed)}updateEluWorkerUsage(e,t){const s=this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu;E(e.elu.active,s,t.taskPerformance?.elu?.active??0,e.tasks.executed),E(e.elu.idle,s,t.taskPerformance?.elu?.idle??0,e.tasks.executed),s.aggregate&&null!=t.taskPerformance?.elu&&(null!=e.elu.utilization?e.elu.utilization=(e.elu.utilization+t.taskPerformance.elu.utilization)/2:e.elu.utilization=t.taskPerformance.elu.utilization)}chooseWorkerNode(){if(this.shallCreateDynamicWorker()){const e=this.createAndSetupDynamicWorkerNode();if(this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker)return e}return this.workerChoiceStrategyContext.execute()}shallCreateDynamicWorker(){return this.type===m.dynamic&&!this.full&&this.internalBusy()}createAndSetupWorkerNode(){const e=this.createWorker();e.on("message",this.opts.messageHandler??y),e.on("error",this.opts.errorHandler??y),e.on("error",(t=>{const s=this.getWorkerNodeKeyByWorker(e),r=this.getWorkerInfo(s);r.ready=!1,this.workerNodes[s].closeChannel(),this.emitter?.emit(p.error,t),!0!==this.opts.restartWorkerOnError||this.starting||(r.dynamic?this.createAndSetupDynamicWorkerNode():this.createAndSetupWorkerNode()),!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(s)})),e.on("online",this.opts.onlineHandler??y),e.on("exit",this.opts.exitHandler??y),e.once("exit",(()=>{this.removeWorkerNode(e)}));const t=this.addWorkerNode(e);return this.afterWorkerNodeSetup(t),t}createAndSetupDynamicWorkerNode(){const e=this.createAndSetupWorkerNode();this.registerWorkerMessageListener(e,(e=>{const t=this.getWorkerNodeKeyByWorkerId(e.workerId),s=this.workerNodes[t].usage;var r;r=I.HARD,(e.kill===r||null!=e.kill&&(!1===this.opts.enableTasksQueue&&0===s.tasks.executing||!0===this.opts.enableTasksQueue&&0===s.tasks.executing&&0===this.tasksQueueSize(t)))&&this.destroyWorkerNode(t).catch(y)}));const t=this.getWorkerInfo(e);return this.sendToWorker(e,{checkActive:!0,workerId:t.id}),t.dynamic=!0,this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker&&(t.ready=!0),e}afterWorkerNodeSetup(e){this.registerWorkerMessageListener(e,this.workerListener()),this.sendStartupMessageToWorker(e),this.sendWorkerStatisticsMessageToWorker(e)}sendWorkerStatisticsMessageToWorker(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate},workerId:this.getWorkerInfo(e).id})}redistributeQueuedTasks(e){for(;this.tasksQueueSize(e)>0;){let t=e,s=1/0,r=!1;for(const[i,o]of this.workerNodes.entries()){const n=this.getWorkerInfo(i);if(i!==e&&n.ready&&0===o.usage.tasks.queued){this.workerNodes[i].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&(r=!0),t=i;break}i!==e&&n.ready&&o.usage.tasks.queued<s&&(s=o.usage.tasks.queued,t=i)}r?this.executeTask(t,this.dequeueTask(e)):this.enqueueTask(t,this.dequeueTask(e))}}workerListener(){return e=>{this.checkMessageWorkerId(e),null!=e.ready?this.handleWorkerReadyResponse(e):null!=e.taskId&&this.handleTaskExecutionResponse(e)}}handleWorkerReadyResponse(e){this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId)).ready=e.ready,null!=this.emitter&&this.ready&&this.emitter.emit(p.ready,this.info)}handleTaskExecutionResponse(e){const t=this.promiseResponseMap.get(e.taskId);if(null!=t){null!=e.taskError?(this.emitter?.emit(p.taskError,e.taskError),t.reject(e.taskError.message)):t.resolve(e.data);const s=t.workerNodeKey;this.afterTaskExecutionHook(s,e),this.promiseResponseMap.delete(e.taskId),!0===this.opts.enableTasksQueue&&this.tasksQueueSize(s)>0&&this.workerNodes[s].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&this.executeTask(s,this.dequeueTask(s)),this.workerChoiceStrategyContext.update(s)}}checkAndEmitEvents(){null!=this.emitter&&(this.busy&&this.emitter.emit(p.busy,this.info),this.type===m.dynamic&&this.full&&this.emitter.emit(p.full,this.info))}getWorkerInfo(e){return this.workerNodes[e].info}addWorkerNode(e){const t=new F(e,this.worker);this.starting&&(t.info.ready=!0),this.workerNodes.push(t);const s=this.getWorkerNodeKeyByWorker(e);if(-1===s)throw new Error("Worker node not found");return s}removeWorkerNode(e){const t=this.getWorkerNodeKeyByWorker(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategyContext.remove(t))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(e,t,t.transferList)}enqueueTask(e,t){return this.workerNodes[e].enqueueTask(t)}dequeueTask(e){return this.workerNodes[e].dequeueTask()}tasksQueueSize(e){return this.workerNodes[e].tasksQueueSize()}flushTasksQueue(e){for(;this.tasksQueueSize(e)>0;)this.executeTask(e,this.dequeueTask(e));this.workerNodes[e].clearTasksQueue()}flushTasksQueues(){for(const[e]of this.workerNodes.entries())this.flushTasksQueue(e)}}class B extends _{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}setupHook(){a.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return a.isPrimary}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e].worker,s=new Promise((e=>{t.on("exit",(()=>{e()}))}));t.on("disconnect",(()=>{t.kill()})),this.sendToWorker(e,{kill:!0,workerId:t.id}),t.disconnect(),await s}sendToWorker(e,t){this.workerNodes[e].worker.send(t)}sendStartupMessageToWorker(e){this.sendToWorker(e,{ready:!1,workerId:this.workerNodes[e].worker.id})}registerWorkerMessageListener(e,t){this.workerNodes[e].worker.on("message",t)}createWorker(){return a.fork(this.opts.env)}get type(){return m.fixed}get worker(){return D.cluster}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}class L extends B{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return m.dynamic}get maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}}class V extends _{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}isMain(){return s}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e],s=t.worker,r=new Promise((e=>{s.on("exit",(()=>{e()}))}));this.sendToWorker(e,{kill:!0,workerId:s.threadId}),t.closeChannel(),await s.terminate(),await r}sendToWorker(e,t,s){this.getWorkerInfo(e).messageChannel.port1.postMessage(t,s)}sendStartupMessageToWorker(e){const t=this.workerNodes[e].worker,s=this.getWorkerInfo(e).messageChannel.port2;t.postMessage({ready:!1,workerId:t.threadId,port:s},[s])}registerWorkerMessageListener(e,t){this.getWorkerInfo(e).messageChannel.port1.on("message",t)}createWorker(){return new r(this.filePath,{env:i,...this.opts.workerOptions})}get type(){return m.fixed}get worker(){return D.thread}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}class j extends V{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return m.dynamic}get maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}}const H=6e4,$=I.SOFT;class G extends l{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,s,r,i={killBehavior:$,maxInactiveTime:H}){super(e),this.isMain=t,this.mainWorker=s,this.opts=i,this.checkWorkerOptions(this.opts),this.checkTaskFunctions(r),this.isMain||this.getMainWorker()?.on("message",this.handleReadyMessage.bind(this))}checkWorkerOptions(e){this.opts.killBehavior=e.killBehavior??$,this.opts.maxInactiveTime=e.maxInactiveTime??H,delete this.opts.async}checkTaskFunctions(e){if(null==e)throw new Error("taskFunctions parameter is mandatory");if(this.taskFunctions=new Map,"function"==typeof e){const t=e.bind(this);this.taskFunctions.set(w,t),this.taskFunctions.set("string"==typeof e.name&&e.name.trim().length>0?e.name:"fn1",t)}else{if(!S(e))throw new TypeError("taskFunctions parameter is not a function or a plain object");{let t=!0;for(const[s,r]of Object.entries(e)){if("string"!=typeof s)throw new TypeError("A taskFunctions parameter object key is not a string");if("function"!=typeof r)throw new TypeError("A taskFunctions parameter object value is not a function");const e=r.bind(this);t&&(this.taskFunctions.set(w,e),t=!1),this.taskFunctions.set(s,e)}if(t)throw new Error("taskFunctions parameter object is empty")}}}hasTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");return this.taskFunctions.has(e)}addTaskFunction(e,t){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===w)throw new Error("Cannot add a task function with the default reserved name");if("function"!=typeof t)throw new TypeError("fn parameter is not a function");try{const s=t.bind(this);return this.taskFunctions.get(e)===this.taskFunctions.get(w)&&this.taskFunctions.set(w,s),this.taskFunctions.set(e,s),!0}catch{return!1}}removeTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===w)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(w))throw new Error("Cannot remove the task function used as the default task function");return this.taskFunctions.delete(e)}listTaskFunctions(){return[...this.taskFunctions.keys()]}setDefaultTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if(e===w)throw new Error("Cannot set the default task function reserved name as the default task function");if(!this.taskFunctions.has(e))throw new Error("Cannot set the default task function to a non-existing task function");try{return this.taskFunctions.set(w,this.taskFunctions.get(e)),!0}catch{return!1}}messageListener(e){if(null!=e.workerId&&e.workerId!==this.id)throw new Error("Message worker id does not match worker id");e.workerId===this.id&&(null!=e.statistics?this.statistics=e.statistics:null!=e.checkActive?!this.isMain&&e.checkActive?this.startCheckActive():this.stopCheckActive():null!=e.taskId&&null!=e.data?this.run(e):!0===e.kill&&this.handleKillMessage(e))}handleKillMessage(e){!this.isMain&&this.stopCheckActive(),this.emitDestroy()}startCheckActive(){this.lastTaskTimestamp=u.now(),this.activeInterval=setInterval(this.checkActive.bind(this),(this.opts.maxInactiveTime??H)/2)}stopCheckActive(){null!=this.activeInterval&&(clearInterval(this.activeInterval),delete this.activeInterval)}checkActive(){u.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??H)&&this.sendToMainWorker({kill:this.opts.killBehavior,workerId:this.id})}getMainWorker(){if(null==this.mainWorker)throw new Error("Main worker not set");return this.mainWorker}handleError(e){return e instanceof Error?e.message:e}run(e){if(this.isMain)throw new Error("Cannot run a task in the main worker");const t=this.getTaskFunction(e.name);(e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name)(t)?this.runInAsyncScope(this.runAsync.bind(this),this,t,e):this.runInAsyncScope(this.runSync.bind(this),this,t,e)}runSync(e,t){try{let s=this.beginTaskPerformance(t.name);const r=e(t.data);s=this.endTaskPerformance(s),this.sendToMainWorker({data:r,taskPerformance:s,workerId:this.id,taskId:t.taskId})}catch(e){const s=this.handleError(e);this.sendToMainWorker({taskError:{name:t.name??w,message:s,data:t.data},workerId:this.id,taskId:t.taskId})}finally{this.updateLastTaskTimestamp()}}runAsync(e,t){let s=this.beginTaskPerformance(t.name);e(t.data).then((e=>(s=this.endTaskPerformance(s),this.sendToMainWorker({data:e,taskPerformance:s,workerId:this.id,taskId:t.taskId}),null))).catch((e=>{const s=this.handleError(e);this.sendToMainWorker({taskError:{name:t.name??w,message:s,data:t.data},workerId:this.id,taskId:t.taskId})})).finally((()=>{this.updateLastTaskTimestamp()})).catch(y)}getTaskFunction(e){e=e??w;const t=this.taskFunctions.get(e);if(null==t)throw new Error(`Task function '${e}' not found`);return t}beginTaskPerformance(e){return this.checkStatistics(),{name:e??w,timestamp:u.now(),...this.statistics.elu&&{elu:u.eventLoopUtilization()}}}endTaskPerformance(e){return this.checkStatistics(),{...e,...this.statistics.runTime&&{runTime:u.now()-e.timestamp},...this.statistics.elu&&{elu:u.eventLoopUtilization(e.elu)}}}checkStatistics(){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set")}updateLastTaskTimestamp(){this.isMain||null==this.activeInterval||(this.lastTaskTimestamp=u.now())}}class Y extends G{constructor(e,t={}){super("worker-cluster-pool:poolifier",a.isPrimary,a.worker,e,t)}handleReadyMessage(e){this.isMain||e.workerId!==this.id||null==e.ready||(this.getMainWorker()?.on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,workerId:this.id}))}get id(){return this.getMainWorker().id}sendToMainWorker(e){this.getMainWorker().send(e)}}class J extends G{port;constructor(e,t={}){super("worker-thread-pool:poolifier",s,o,e,t)}handleReadyMessage(e){this.isMain||e.workerId!==this.id||null==e.ready||null==e.port||(this.port=e.port,this.port.on("message",this.messageListener.bind(this)),this.sendToMainWorker({ready:!0,workerId:this.id}))}handleKillMessage(e){super.handleKillMessage(e),this.port?.unref(),this.port?.close()}get id(){return n}sendToMainWorker(e){this.port.postMessage(e)}handleError(e){return e}}export{Y as ClusterWorker,L as DynamicClusterPool,j as DynamicThreadPool,B as FixedClusterPool,V as FixedThreadPool,I as KillBehaviors,R as Measurements,p as PoolEvents,m as PoolTypes,J as ThreadWorker,b as WorkerChoiceStrategies,D as WorkerTypes,W as availableParallelism};
|
|
1
|
+
import{EventEmitter as e}from"node:events";import{MessageChannel as t,isMainThread as s,Worker as r,SHARE_ENV as i,parentPort as o,threadId as n}from"node:worker_threads";import a from"node:cluster";import{randomUUID as h}from"node:crypto";import{performance as u}from"node:perf_hooks";import{existsSync as k}from"node:fs";import*as c from"node:os";import{cpus as d}from"node:os";import{AsyncResource as l}from"node:async_hooks";const m=Object.freeze({fixed:"fixed",dynamic:"dynamic"});class g extends e{}const p=Object.freeze({full:"full",ready:"ready",busy:"busy",error:"error",taskError:"taskError"}),w="default",y=Object.freeze((()=>{})),f={runTime:{median:!1},waitTime:{median:!1},elu:{median:!1}},T={aggregate:!1,average:!1,median:!1},W=()=>{let e=1;try{e=c.availableParallelism()}catch{const t=c.cpus();Array.isArray(t)&&t.length>0&&(e=t.length)}return e},N=e=>{if(Array.isArray(e)&&0===e.length)return 0;if(Array.isArray(e)&&1===e.length)return e[0];const t=e.slice().sort(((e,t)=>e-t));return(t[t.length-1>>1]+t[t.length>>1])/2},x=(e,t=2)=>{const s=Math.pow(10,t);return Math.round(e*s*(1+Number.EPSILON))/s},S=e=>"object"==typeof e&&null!==e&&e?.constructor===Object&&"[object Object]"===Object.prototype.toString.call(e),E=(e,t)=>t===e,I=e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name,b=(e,t,s,r)=>{t.aggregate&&(e.aggregate=(e.aggregate??0)+s,e.minimum=Math.min(s,e.minimum??1/0),e.maximum=Math.max(s,e.maximum??-1/0),t.average&&0!==r&&(e.average=e.aggregate/r),t.median&&null!=s&&(e.history.push(s),e.median=N(e.history)))},R=Object.freeze({SOFT:"SOFT",HARD:"HARD"}),C=Object.freeze({ROUND_ROBIN:"ROUND_ROBIN",LEAST_USED:"LEAST_USED",LEAST_BUSY:"LEAST_BUSY",LEAST_ELU:"LEAST_ELU",FAIR_SHARE:"FAIR_SHARE",WEIGHTED_ROUND_ROBIN:"WEIGHTED_ROUND_ROBIN",INTERLEAVED_WEIGHTED_ROUND_ROBIN:"INTERLEAVED_WEIGHTED_ROUND_ROBIN"}),v=Object.freeze({runTime:"runTime",waitTime:"waitTime",elu:"elu"});class O{pool;opts;nextWorkerNodeKey=0;strategyPolicy={useDynamicWorker:!1};taskStatisticsRequirements={runTime:T,waitTime:T,elu:T};constructor(e,t=f){this.pool=e,this.opts=t,this.choose=this.choose.bind(this)}setTaskStatisticsRequirements(e){this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.runTime,e.runTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.waitTime,e.waitTime?.median),this.toggleMedianMeasurementStatisticsRequirements(this.taskStatisticsRequirements.elu,e.elu?.median)}toggleMedianMeasurementStatisticsRequirements(e,t){e.average&&t&&(e.average=!1,e.median=t),e.median&&!t&&(e.average=!0,e.median=t)}setOptions(e){this.opts=e??f,this.setTaskStatisticsRequirements(this.opts)}isWorkerNodeReady(e){return this.pool.workerNodes[e].info.ready}getWorkerTaskRunTime(e){return this.taskStatisticsRequirements.runTime.median?this.pool.workerNodes[e].usage.runTime?.median??0:this.pool.workerNodes[e].usage.runTime?.average??0}getWorkerTaskWaitTime(e){return this.taskStatisticsRequirements.waitTime.median?this.pool.workerNodes[e].usage.waitTime?.median??0:this.pool.workerNodes[e].usage.waitTime?.average??0}getWorkerTaskElu(e){return this.taskStatisticsRequirements.elu.median?this.pool.workerNodes[e].usage.elu.active?.median??0:this.pool.workerNodes[e].usage.elu.active?.average??0}computeDefaultWorkerWeight(){let e=0;for(const t of d()){const s=t.speed.toString().length-1;e+=1/(t.speed/Math.pow(10,s))*Math.pow(10,s)}return Math.round(e/d().length)}}class z extends O{taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:T,elu:{aggregate:!0,average:!0,median:!1}};workersVirtualTaskEndTimestamp=[];constructor(e,t=f){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.workersVirtualTaskEndTimestamp=[],!0}update(e){return this.computeWorkerVirtualTaskEndTimestamp(e),!0}choose(){return this.fairShareNextWorkerNodeKey()}remove(e){return this.workersVirtualTaskEndTimestamp.splice(e,1),!0}fairShareNextWorkerNodeKey(){let e=1/0;for(const[t]of this.pool.workerNodes.entries()){null==this.workersVirtualTaskEndTimestamp[t]&&this.computeWorkerVirtualTaskEndTimestamp(t);const s=this.workersVirtualTaskEndTimestamp[t];this.isWorkerNodeReady(t)&&s<e&&(e=s,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}computeWorkerVirtualTaskEndTimestamp(e){this.workersVirtualTaskEndTimestamp[e]=this.getWorkerVirtualTaskEndTimestamp(e,this.getWorkerVirtualTaskStartTimestamp(e))}getWorkerVirtualTaskEndTimestamp(e,t){return t+(this.opts.measurement===v.elu?this.getWorkerTaskElu(e):this.getWorkerTaskRunTime(e))}getWorkerVirtualTaskStartTimestamp(e){return Math.max(performance.now(),this.workersVirtualTaskEndTimestamp[e]??-1/0)}}class M extends O{strategyPolicy={useDynamicWorker:!0};roundId=0;roundWeights;defaultWorkerWeight;constructor(e,t=f){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight(),this.roundWeights=this.getRoundWeights()}reset(){return this.nextWorkerNodeKey=0,this.roundId=0,!0}update(){return!0}choose(){let e,t;for(let s=this.roundId;s<this.roundWeights.length;s++)for(let r=this.nextWorkerNodeKey;r<this.pool.workerNodes.length;r++){const i=this.opts.weights?.[r]??this.defaultWorkerWeight;if(this.isWorkerNodeReady(r)&&i>=this.roundWeights[s]){e=s,t=r;break}}this.roundId=e??0,this.nextWorkerNodeKey=t??0;const s=this.nextWorkerNodeKey;return this.nextWorkerNodeKey===this.pool.workerNodes.length-1?(this.nextWorkerNodeKey=0,this.roundId=this.roundId===this.roundWeights.length-1?0:this.roundId+1):this.nextWorkerNodeKey=this.nextWorkerNodeKey+1,s}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1,this.roundId=this.roundId===this.roundWeights.length-1?0:this.roundId+1)),!0}setOptions(e){super.setOptions(e),this.roundWeights=this.getRoundWeights()}getRoundWeights(){return null==this.opts.weights?[this.defaultWorkerWeight]:[...new Set(Object.values(this.opts.weights).slice().sort(((e,t)=>e-t)))]}}class K extends O{taskStatisticsRequirements={runTime:{aggregate:!0,average:!1,median:!1},waitTime:{aggregate:!0,average:!1,median:!1},elu:T};constructor(e,t=f){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.leastBusyNextWorkerNodeKey()}remove(){return!0}leastBusyNextWorkerNodeKey(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=(s.usage.runTime?.aggregate??0)+(s.usage.waitTime?.aggregate??0);if(this.isWorkerNodeReady(t)&&0===r){this.nextWorkerNodeKey=t;break}this.isWorkerNodeReady(t)&&r<e&&(e=r,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}}class q extends O{constructor(e,t=f){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.leastUsedNextWorkerNodeKey()}remove(){return!0}leastUsedNextWorkerNodeKey(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=s.usage.tasks,i=r.executed+r.executing+r.queued;if(this.isWorkerNodeReady(t)&&0===i){this.nextWorkerNodeKey=t;break}this.isWorkerNodeReady(t)&&i<e&&(e=i,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}}class Q extends O{taskStatisticsRequirements={runTime:T,waitTime:T,elu:{aggregate:!0,average:!1,median:!1}};constructor(e,t=f){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return!0}update(){return!0}choose(){return this.leastEluNextWorkerNodeKey()}remove(){return!0}leastEluNextWorkerNodeKey(){let e=1/0;for(const[t,s]of this.pool.workerNodes.entries()){const r=s.usage,i=r.elu?.active?.aggregate??0;if(this.isWorkerNodeReady(t)&&0===i){this.nextWorkerNodeKey=t;break}this.isWorkerNodeReady(t)&&i<e&&(e=i,this.nextWorkerNodeKey=t)}return this.nextWorkerNodeKey}}class F extends O{strategyPolicy={useDynamicWorker:!0};constructor(e,t=f){super(e,t),this.setTaskStatisticsRequirements(this.opts)}reset(){return this.nextWorkerNodeKey=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;do{this.roundRobinNextWorkerNodeKey()}while(!this.isWorkerNodeReady(this.nextWorkerNodeKey));return e}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1)),!0}roundRobinNextWorkerNodeKey(){return this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:this.nextWorkerNodeKey+1,this.nextWorkerNodeKey}}class A extends O{strategyPolicy={useDynamicWorker:!0};taskStatisticsRequirements={runTime:{aggregate:!0,average:!0,median:!1},waitTime:T,elu:T};defaultWorkerWeight;workerVirtualTaskRunTime=0;constructor(e,t=f){super(e,t),this.setTaskStatisticsRequirements(this.opts),this.defaultWorkerWeight=this.computeDefaultWorkerWeight()}reset(){return this.nextWorkerNodeKey=0,this.workerVirtualTaskRunTime=0,!0}update(){return!0}choose(){const e=this.nextWorkerNodeKey;do{this.weightedRoundRobinNextWorkerNodeKey()}while(!this.isWorkerNodeReady(this.nextWorkerNodeKey));return e}remove(e){return this.nextWorkerNodeKey===e&&(0===this.pool.workerNodes.length?this.nextWorkerNodeKey=0:this.nextWorkerNodeKey>this.pool.workerNodes.length-1&&(this.nextWorkerNodeKey=this.pool.workerNodes.length-1),this.workerVirtualTaskRunTime=0),!0}weightedRoundRobinNextWorkerNodeKey(){const e=this.workerVirtualTaskRunTime;return e<(this.opts.weights?.[this.nextWorkerNodeKey]??this.defaultWorkerWeight)?this.workerVirtualTaskRunTime=e+this.getWorkerTaskRunTime(this.nextWorkerNodeKey):(this.nextWorkerNodeKey=this.nextWorkerNodeKey===this.pool.workerNodes.length-1?0:this.nextWorkerNodeKey+1,this.workerVirtualTaskRunTime=0),this.nextWorkerNodeKey}}class U{workerChoiceStrategy;workerChoiceStrategies;constructor(e,t=C.ROUND_ROBIN,s=f){this.workerChoiceStrategy=t,this.execute=this.execute.bind(this),this.workerChoiceStrategies=new Map([[C.ROUND_ROBIN,new(F.bind(this))(e,s)],[C.LEAST_USED,new(q.bind(this))(e,s)],[C.LEAST_BUSY,new(K.bind(this))(e,s)],[C.LEAST_ELU,new(Q.bind(this))(e,s)],[C.FAIR_SHARE,new(z.bind(this))(e,s)],[C.WEIGHTED_ROUND_ROBIN,new(A.bind(this))(e,s)],[C.INTERLEAVED_WEIGHTED_ROUND_ROBIN,new(M.bind(this))(e,s)]])}getStrategyPolicy(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).strategyPolicy}getTaskStatisticsRequirements(){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).taskStatisticsRequirements}setWorkerChoiceStrategy(e){this.workerChoiceStrategy!==e&&(this.workerChoiceStrategy=e),this.workerChoiceStrategies.get(this.workerChoiceStrategy)?.reset()}update(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).update(e)}execute(){const e=this.workerChoiceStrategies.get(this.workerChoiceStrategy).choose();if(null==e)throw new TypeError("Worker node key chosen is null or undefined");return e}remove(e){return this.workerChoiceStrategies.get(this.workerChoiceStrategy).remove(e)}setOptions(e){for(const t of this.workerChoiceStrategies.values())t.setOptions(e)}}class P extends Array{size;constructor(e=1024,...t){super(),this.checkSize(e),this.size=e,arguments.length>1&&this.push(...t)}push(...e){const t=super.push(...e);return t>this.size&&super.splice(0,t-this.size),this.length}unshift(...e){return super.unshift(...e)>this.size&&super.splice(this.size,e.length),this.length}concat(...e){const t=super.concat(e);return t.size=this.size,t.length>t.size&&t.splice(0,t.length-t.size),t}splice(e,t,...s){let r=[];if(arguments.length>=3&&null!=t){if(r=super.splice(e,t,...s),this.length>this.size){const e=super.splice(0,this.length-this.size);r=new P(r.length+e.length,...r,...e)}}else r=2===arguments.length?super.splice(e,t):super.splice(e);return r}resize(e){if(this.checkSize(e),0===e)this.length=0;else if(e<this.size)for(let t=e;t<this.size;t++)super.pop();this.size=e}empty(){return 0===this.length}full(){return this.length===this.size}checkSize(e){if(!Number.isSafeInteger(e))throw new TypeError(`Invalid circular array size: ${e} is not a safe integer`);if(e<0)throw new RangeError(`Invalid circular array size: ${e} < 0`)}}class D{items;offset;size;maxSize;constructor(){this.clear()}enqueue(e){return this.items.push(e),++this.size,this.size>this.maxSize&&(this.maxSize=this.size),this.size}dequeue(){if(this.size<=0)return;const e=this.items[this.offset];return 2*++this.offset>=this.items.length&&(this.items=this.items.slice(this.offset),this.offset=0),--this.size,e}peek(){if(!(this.size<=0))return this.items[this.offset]}clear(){this.items=[],this.offset=0,this.size=0,this.maxSize=0}[Symbol.iterator](){const e=this.items;let t=this.offset;return{next:()=>{if(t>=e.length)return{value:void 0,done:!0};const s=e[t];return++t,{value:s,done:!1}}}}}const L=Object.freeze({thread:"thread",cluster:"cluster"});class _{worker;info;usage;tasksUsage;tasksQueue;constructor(e,t){this.worker=e,this.info=this.initWorkerInfo(e,t),this.usage=this.initWorkerUsage(),this.tasksUsage=new Map,this.tasksQueue=new D}tasksQueueSize(){return this.tasksQueue.size}tasksQueueMaxSize(){return this.tasksQueue.maxSize}enqueueTask(e){return this.tasksQueue.enqueue(e)}dequeueTask(){return this.tasksQueue.dequeue()}clearTasksQueue(){this.tasksQueue.clear()}resetUsage(){this.usage=this.initWorkerUsage(),this.tasksUsage.clear()}closeChannel(){null!=this.info.messageChannel&&(this.info.messageChannel?.port1.unref(),this.info.messageChannel?.port2.unref(),this.info.messageChannel?.port1.close(),this.info.messageChannel?.port2.close(),delete this.info.messageChannel)}getTaskWorkerUsage(e){return this.tasksUsage.has(e)||this.tasksUsage.set(e,this.initTaskWorkerUsage(e)),this.tasksUsage.get(e)}initWorkerInfo(e,s){return{id:this.getWorkerId(e,s),type:s,dynamic:!1,ready:!1,...s===L.thread&&{messageChannel:new t}}}initWorkerUsage(){const e=()=>this.tasksQueueSize(),t=()=>this.tasksQueueMaxSize();return{tasks:{executed:0,executing:0,get queued(){return e()},get maxQueued(){return t()},failed:0},runTime:{history:new P},waitTime:{history:new P},elu:{idle:{history:new P},active:{history:new P}}}}initTaskWorkerUsage(e){const t=()=>{let t=0;for(const s of this.tasksQueue)s.name===e&&++t;return t};return{tasks:{executed:0,executing:0,get queued(){return t()},failed:0},runTime:{history:new P},waitTime:{history:new P},elu:{idle:{history:new P},active:{history:new P}}}}getWorkerId(e,t){return t===L.thread?e.threadId:t===L.cluster?e.id:void 0}}class B{numberOfWorkers;filePath;opts;workerNodes=[];emitter;promiseResponseMap=new Map;workerChoiceStrategyContext;starting;startTimestamp;taskFunctions;constructor(e,t,s){if(this.numberOfWorkers=e,this.filePath=t,this.opts=s,!this.isMain())throw new Error("Cannot start a pool from a worker with the same type as the pool");this.checkNumberOfWorkers(this.numberOfWorkers),this.checkFilePath(this.filePath),this.checkPoolOptions(this.opts),this.chooseWorkerNode=this.chooseWorkerNode.bind(this),this.executeTask=this.executeTask.bind(this),this.enqueueTask=this.enqueueTask.bind(this),this.dequeueTask=this.dequeueTask.bind(this),this.checkAndEmitEvents=this.checkAndEmitEvents.bind(this),!0===this.opts.enableEvents&&(this.emitter=new g),this.workerChoiceStrategyContext=new U(this,this.opts.workerChoiceStrategy,this.opts.workerChoiceStrategyOptions),this.setupHook(),this.starting=!0,this.startPool(),this.starting=!1,this.startTimestamp=u.now()}checkFilePath(e){if(null==e||"string"!=typeof e||"string"==typeof e&&0===e.trim().length)throw new Error("Please specify a file with a worker implementation");if(!k(e))throw new Error(`Cannot find the worker file '${e}'`)}checkNumberOfWorkers(e){if(null==e)throw new Error("Cannot instantiate a pool without specifying the number of workers");if(!Number.isSafeInteger(e))throw new TypeError("Cannot instantiate a pool with a non safe integer number of workers");if(e<0)throw new RangeError("Cannot instantiate a pool with a negative number of workers");if(this.type===m.fixed&&0===e)throw new RangeError("Cannot instantiate a fixed pool with zero worker")}checkDynamicPoolSize(e,t){if(this.type===m.dynamic){if(null==t)throw new Error("Cannot instantiate a dynamic pool without specifying the maximum pool size");if(!Number.isSafeInteger(t))throw new TypeError("Cannot instantiate a dynamic pool with a non safe integer maximum pool size");if(e>t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size");if(0===t)throw new RangeError("Cannot instantiate a dynamic pool with a maximum pool size equal to zero");if(e===t)throw new RangeError("Cannot instantiate a dynamic pool with a minimum pool size equal to the maximum pool size. Use a fixed pool instead")}}checkPoolOptions(e){if(!S(e))throw new TypeError("Invalid pool options: must be a plain object");this.opts.workerChoiceStrategy=e.workerChoiceStrategy??C.ROUND_ROBIN,this.checkValidWorkerChoiceStrategy(this.opts.workerChoiceStrategy),this.opts.workerChoiceStrategyOptions=e.workerChoiceStrategyOptions??f,this.checkValidWorkerChoiceStrategyOptions(this.opts.workerChoiceStrategyOptions),this.opts.restartWorkerOnError=e.restartWorkerOnError??!0,this.opts.enableEvents=e.enableEvents??!0,this.opts.enableTasksQueue=e.enableTasksQueue??!1,this.opts.enableTasksQueue&&(this.checkValidTasksQueueOptions(e.tasksQueueOptions),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e.tasksQueueOptions))}checkValidWorkerChoiceStrategy(e){if(!Object.values(C).includes(e))throw new Error(`Invalid worker choice strategy '${e}'`)}checkValidWorkerChoiceStrategyOptions(e){if(!S(e))throw new TypeError("Invalid worker choice strategy options: must be a plain object");if(null!=e.weights&&Object.keys(e.weights).length!==this.maxSize)throw new Error("Invalid worker choice strategy options: must have a weight for each worker node");if(null!=e.measurement&&!Object.values(v).includes(e.measurement))throw new Error(`Invalid worker choice strategy options: invalid measurement '${e.measurement}'`)}checkValidTasksQueueOptions(e){if(null!=e&&!S(e))throw new TypeError("Invalid tasks queue options: must be a plain object");if(null!=e?.concurrency&&!Number.isSafeInteger(e.concurrency))throw new TypeError("Invalid worker tasks concurrency: must be an integer");if(null!=e?.concurrency&&e.concurrency<=0)throw new Error(`Invalid worker tasks concurrency '${e.concurrency}'`)}startPool(){for(;this.workerNodes.reduce(((e,t)=>t.info.dynamic?e:e+1),0)<this.numberOfWorkers;)this.createAndSetupWorkerNode()}get info(){return{version:"2.6.26",type:this.type,worker:this.worker,ready:this.ready,strategy:this.opts.workerChoiceStrategy,minSize:this.minSize,maxSize:this.maxSize,...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{utilization:x(this.utilization)},workerNodes:this.workerNodes.length,idleWorkerNodes:this.workerNodes.reduce(((e,t)=>0===t.usage.tasks.executing?e+1:e),0),busyWorkerNodes:this.workerNodes.reduce(((e,t)=>t.usage.tasks.executing>0?e+1:e),0),executedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executed),0),executingTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.executing),0),...!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)},failedTasks:this.workerNodes.reduce(((e,t)=>e+t.usage.tasks.failed),0),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate&&{runTime:{minimum:x(Math.min(...this.workerNodes.map((e=>e.usage.runTime?.minimum??1/0)))),maximum:x(Math.max(...this.workerNodes.map((e=>e.usage.runTime?.maximum??-1/0)))),average:x(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)/this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.executed??0)),0)),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.median&&{median:x(N(this.workerNodes.map((e=>e.usage.runTime?.median??0))))}}},...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.aggregate&&{waitTime:{minimum:x(Math.min(...this.workerNodes.map((e=>e.usage.waitTime?.minimum??1/0)))),maximum:x(Math.max(...this.workerNodes.map((e=>e.usage.waitTime?.maximum??-1/0)))),average:x(this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0)/this.workerNodes.reduce(((e,t)=>e+(t.usage.tasks?.executed??0)),0)),...this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime.median&&{median:x(N(this.workerNodes.map((e=>e.usage.waitTime?.median??0))))}}}}}get ready(){return this.workerNodes.reduce(((e,t)=>!t.info.dynamic&&t.info.ready?e+1:e),0)>=this.minSize}get utilization(){const e=(u.now()-this.startTimestamp)*this.maxSize;return(this.workerNodes.reduce(((e,t)=>e+(t.usage.runTime?.aggregate??0)),0)+this.workerNodes.reduce(((e,t)=>e+(t.usage.waitTime?.aggregate??0)),0))/e}checkMessageWorkerId(e){if(null!=e.workerId&&-1===this.getWorkerNodeKeyByWorkerId(e.workerId))throw new Error(`Worker message received from unknown worker '${e.workerId}'`)}getWorkerNodeKeyByWorker(e){return this.workerNodes.findIndex((t=>t.worker===e))}getWorkerNodeKeyByWorkerId(e){return this.workerNodes.findIndex((t=>t.info.id===e))}setWorkerChoiceStrategy(e,t){this.checkValidWorkerChoiceStrategy(e),this.opts.workerChoiceStrategy=e,this.workerChoiceStrategyContext.setWorkerChoiceStrategy(this.opts.workerChoiceStrategy),null!=t&&this.setWorkerChoiceStrategyOptions(t);for(const[e,t]of this.workerNodes.entries())t.resetUsage(),this.sendStatisticsMessageToWorker(e)}setWorkerChoiceStrategyOptions(e){this.checkValidWorkerChoiceStrategyOptions(e),this.opts.workerChoiceStrategyOptions=e,this.workerChoiceStrategyContext.setOptions(this.opts.workerChoiceStrategyOptions)}enableTasksQueue(e,t){!0!==this.opts.enableTasksQueue||e||this.flushTasksQueues(),this.opts.enableTasksQueue=e,this.setTasksQueueOptions(t)}setTasksQueueOptions(e){!0===this.opts.enableTasksQueue?(this.checkValidTasksQueueOptions(e),this.opts.tasksQueueOptions=this.buildTasksQueueOptions(e)):null!=this.opts.tasksQueueOptions&&delete this.opts.tasksQueueOptions}buildTasksQueueOptions(e){return{concurrency:e?.concurrency??1}}get full(){return this.workerNodes.length>=this.maxSize}internalBusy(){return!0===this.opts.enableTasksQueue?-1===this.workerNodes.findIndex((e=>e.info.ready&&e.usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency)):-1===this.workerNodes.findIndex((e=>e.info.ready&&0===e.usage.tasks.executing))}listTaskFunctions(){return null!=this.taskFunctions?this.taskFunctions:[]}async execute(e,t,s){return await new Promise(((r,i)=>{null!=t&&"string"!=typeof t&&i(new TypeError("name argument must be a string")),null!=t&&"string"==typeof t&&0===t.trim().length&&i(new TypeError("name argument must not be an empty string")),null==t||null==this.taskFunctions||this.taskFunctions.includes(t)||i(new Error(`Task function '${t}' is not registered in the pool`)),null==s||Array.isArray(s)||i(new TypeError("transferList argument must be an array"));const o=u.now(),n=this.chooseWorkerNode(),a={name:t??w,data:e??{},transferList:s,timestamp:o,workerId:this.getWorkerInfo(n).id,taskId:h()};this.promiseResponseMap.set(a.taskId,{resolve:r,reject:i,workerNodeKey:n}),!1===this.opts.enableTasksQueue||!0===this.opts.enableTasksQueue&&this.workerNodes[n].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency?this.executeTask(n,a):this.enqueueTask(n,a),this.checkAndEmitEvents()}))}async destroy(){await Promise.all(this.workerNodes.map((async(e,t)=>{await this.destroyWorkerNode(t)})))}async sendKillMessageToWorker(e,t){await new Promise(((s,r)=>{this.registerWorkerMessageListener(e,(e=>{"success"===e.kill?s():"failure"===e.kill&&r(new Error(`Worker ${t} kill message handling failed`))})),this.sendToWorker(e,{kill:!0,workerId:t})}))}setupHook(){}beforeTaskExecutionHook(e,t){const s=this.workerNodes[e].usage;++s.tasks.executing,this.updateWaitTimeWorkerUsage(s,t);const r=this.workerNodes[e].getTaskWorkerUsage(t.name);++r.tasks.executing,this.updateWaitTimeWorkerUsage(r,t)}afterTaskExecutionHook(e,t){const s=this.workerNodes[e].usage;this.updateTaskStatisticsWorkerUsage(s,t),this.updateRunTimeWorkerUsage(s,t),this.updateEluWorkerUsage(s,t);const r=this.workerNodes[e].getTaskWorkerUsage(t.taskPerformance?.name??w);this.updateTaskStatisticsWorkerUsage(r,t),this.updateRunTimeWorkerUsage(r,t),this.updateEluWorkerUsage(r,t)}updateTaskStatisticsWorkerUsage(e,t){const s=e.tasks;--s.executing,null==t.taskError?++s.executed:++s.failed}updateRunTimeWorkerUsage(e,t){b(e.runTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime,t.taskPerformance?.runTime??0,e.tasks.executed)}updateWaitTimeWorkerUsage(e,t){const s=u.now(),r=s-(t.timestamp??s);b(e.waitTime,this.workerChoiceStrategyContext.getTaskStatisticsRequirements().waitTime,r,e.tasks.executed)}updateEluWorkerUsage(e,t){const s=this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu;b(e.elu.active,s,t.taskPerformance?.elu?.active??0,e.tasks.executed),b(e.elu.idle,s,t.taskPerformance?.elu?.idle??0,e.tasks.executed),s.aggregate&&null!=t.taskPerformance?.elu&&(null!=e.elu.utilization?e.elu.utilization=(e.elu.utilization+t.taskPerformance.elu.utilization)/2:e.elu.utilization=t.taskPerformance.elu.utilization)}chooseWorkerNode(){if(this.shallCreateDynamicWorker()){const e=this.createAndSetupDynamicWorkerNode();if(this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker)return e}return this.workerChoiceStrategyContext.execute()}shallCreateDynamicWorker(){return this.type===m.dynamic&&!this.full&&this.internalBusy()}createAndSetupWorkerNode(){const e=this.createWorker();e.on("message",this.opts.messageHandler??y),e.on("error",this.opts.errorHandler??y),e.on("error",(t=>{const s=this.getWorkerNodeKeyByWorker(e),r=this.getWorkerInfo(s);r.ready=!1,this.workerNodes[s].closeChannel(),this.emitter?.emit(p.error,t),!0!==this.opts.restartWorkerOnError||this.starting||(r.dynamic?this.createAndSetupDynamicWorkerNode():this.createAndSetupWorkerNode()),!0===this.opts.enableTasksQueue&&this.redistributeQueuedTasks(s)})),e.on("online",this.opts.onlineHandler??y),e.on("exit",this.opts.exitHandler??y),e.once("exit",(()=>{this.removeWorkerNode(e)}));const t=this.addWorkerNode(e);return this.afterWorkerNodeSetup(t),t}createAndSetupDynamicWorkerNode(){const e=this.createAndSetupWorkerNode();this.registerWorkerMessageListener(e,(e=>{const t=this.getWorkerNodeKeyByWorkerId(e.workerId),s=this.workerNodes[t].usage;(E(R.HARD,e.kill)||E(R.SOFT,e.kill)&&(!1===this.opts.enableTasksQueue&&0===s.tasks.executing||!0===this.opts.enableTasksQueue&&0===s.tasks.executing&&0===this.tasksQueueSize(t)))&&this.destroyWorkerNode(t).catch((e=>{this.emitter?.emit(p.error,e)}))}));const t=this.getWorkerInfo(e);return this.sendToWorker(e,{checkActive:!0,workerId:t.id}),t.dynamic=!0,this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker&&(t.ready=!0),e}afterWorkerNodeSetup(e){this.registerWorkerMessageListener(e,this.workerListener()),this.sendStartupMessageToWorker(e),this.sendStatisticsMessageToWorker(e)}sendStatisticsMessageToWorker(e){this.sendToWorker(e,{statistics:{runTime:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().runTime.aggregate,elu:this.workerChoiceStrategyContext.getTaskStatisticsRequirements().elu.aggregate},workerId:this.getWorkerInfo(e).id})}redistributeQueuedTasks(e){for(;this.tasksQueueSize(e)>0;){let t=e,s=1/0,r=!1;for(const[i,o]of this.workerNodes.entries()){const n=this.getWorkerInfo(i);if(i!==e&&n.ready&&0===o.usage.tasks.queued){this.workerNodes[i].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&(r=!0),t=i;break}i!==e&&n.ready&&o.usage.tasks.queued<s&&(s=o.usage.tasks.queued,t=i)}r?this.executeTask(t,this.dequeueTask(e)):this.enqueueTask(t,this.dequeueTask(e))}}workerListener(){return e=>{this.checkMessageWorkerId(e),null!=e.ready?this.handleWorkerReadyResponse(e):null!=e.taskId?this.handleTaskExecutionResponse(e):null!=e.taskFunctions&&(this.taskFunctions=e.taskFunctions)}}handleWorkerReadyResponse(e){this.getWorkerInfo(this.getWorkerNodeKeyByWorkerId(e.workerId)).ready=e.ready,null!=this.emitter&&this.ready&&this.emitter.emit(p.ready,this.info)}handleTaskExecutionResponse(e){const t=this.promiseResponseMap.get(e.taskId);if(null!=t){null!=e.taskError?(this.emitter?.emit(p.taskError,e.taskError),t.reject(e.taskError.message)):t.resolve(e.data);const s=t.workerNodeKey;this.afterTaskExecutionHook(s,e),this.promiseResponseMap.delete(e.taskId),!0===this.opts.enableTasksQueue&&this.tasksQueueSize(s)>0&&this.workerNodes[s].usage.tasks.executing<this.opts.tasksQueueOptions?.concurrency&&this.executeTask(s,this.dequeueTask(s)),this.workerChoiceStrategyContext.update(s)}}checkAndEmitEvents(){null!=this.emitter&&(this.busy&&this.emitter.emit(p.busy,this.info),this.type===m.dynamic&&this.full&&this.emitter.emit(p.full,this.info))}getWorkerInfo(e){return this.workerNodes[e].info}addWorkerNode(e){const t=new _(e,this.worker);this.starting&&(t.info.ready=!0),this.workerNodes.push(t);const s=this.getWorkerNodeKeyByWorker(e);if(-1===s)throw new Error("Worker node not found");return s}removeWorkerNode(e){const t=this.getWorkerNodeKeyByWorker(e);-1!==t&&(this.workerNodes.splice(t,1),this.workerChoiceStrategyContext.remove(t))}executeTask(e,t){this.beforeTaskExecutionHook(e,t),this.sendToWorker(e,t,t.transferList)}enqueueTask(e,t){return this.workerNodes[e].enqueueTask(t)}dequeueTask(e){return this.workerNodes[e].dequeueTask()}tasksQueueSize(e){return this.workerNodes[e].tasksQueueSize()}flushTasksQueue(e){for(;this.tasksQueueSize(e)>0;)this.executeTask(e,this.dequeueTask(e));this.workerNodes[e].clearTasksQueue()}flushTasksQueues(){for(const[e]of this.workerNodes.entries())this.flushTasksQueue(e)}}class V extends B{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}setupHook(){a.setupPrimary({...this.opts.settings,exec:this.filePath})}isMain(){return a.isPrimary}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e].worker,s=new Promise((e=>{t.on("exit",(()=>{e()}))}));t.on("disconnect",(()=>{t.kill()})),await this.sendKillMessageToWorker(e,t.id),t.disconnect(),await s}sendToWorker(e,t){this.workerNodes[e].worker.send(t)}sendStartupMessageToWorker(e){this.sendToWorker(e,{ready:!1,workerId:this.workerNodes[e].worker.id})}registerWorkerMessageListener(e,t){this.workerNodes[e].worker.on("message",t)}createWorker(){return a.fork(this.opts.env)}get type(){return m.fixed}get worker(){return L.cluster}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}class H extends V{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return m.dynamic}get maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}}class j extends B{opts;constructor(e,t,s={}){super(e,t,s),this.opts=s}isMain(){return s}async destroyWorkerNode(e){this.flushTasksQueue(e);const t=this.workerNodes[e],s=t.worker,r=new Promise((e=>{s.on("exit",(()=>{e()}))}));await this.sendKillMessageToWorker(e,s.threadId),t.closeChannel(),await s.terminate(),await r}sendToWorker(e,t,s){this.getWorkerInfo(e).messageChannel.port1.postMessage(t,s)}sendStartupMessageToWorker(e){const t=this.workerNodes[e].worker,s=this.getWorkerInfo(e).messageChannel.port2;t.postMessage({ready:!1,workerId:t.threadId,port:s},[s])}registerWorkerMessageListener(e,t){this.getWorkerInfo(e).messageChannel.port1.on("message",t)}createWorker(){return new r(this.filePath,{env:i,...this.opts.workerOptions})}get type(){return m.fixed}get worker(){return L.thread}get minSize(){return this.numberOfWorkers}get maxSize(){return this.numberOfWorkers}get busy(){return this.internalBusy()}}class $ extends j{max;constructor(e,t,s,r={}){super(e,s,r),this.max=t,this.checkDynamicPoolSize(this.numberOfWorkers,this.max)}get type(){return m.dynamic}get maxSize(){return this.max}get busy(){return this.full&&this.internalBusy()}}const G=6e4,Y=R.SOFT;class J extends l{isMain;mainWorker;opts;taskFunctions;lastTaskTimestamp;statistics;activeInterval;constructor(e,t,s,r,i={killBehavior:Y,maxInactiveTime:G,killHandler:y}){super(e),this.isMain=t,this.mainWorker=s,this.opts=i,this.checkWorkerOptions(this.opts),this.checkTaskFunctions(r),this.isMain||this.getMainWorker()?.on("message",this.handleReadyMessage.bind(this))}checkWorkerOptions(e){this.opts.killBehavior=e.killBehavior??Y,this.opts.maxInactiveTime=e.maxInactiveTime??G,delete this.opts.async,this.opts.killHandler=e.killHandler??y}checkTaskFunctions(e){if(null==e)throw new Error("taskFunctions parameter is mandatory");if(this.taskFunctions=new Map,"function"==typeof e){const t=e.bind(this);this.taskFunctions.set(w,t),this.taskFunctions.set("string"==typeof e.name&&e.name.trim().length>0?e.name:"fn1",t)}else{if(!S(e))throw new TypeError("taskFunctions parameter is not a function or a plain object");{let t=!0;for(const[s,r]of Object.entries(e)){if("string"!=typeof s)throw new TypeError("A taskFunctions parameter object key is not a string");if("string"==typeof s&&0===s.trim().length)throw new TypeError("A taskFunctions parameter object key an empty string");if("function"!=typeof r)throw new TypeError("A taskFunctions parameter object value is not a function");const e=r.bind(this);t&&(this.taskFunctions.set(w,e),t=!1),this.taskFunctions.set(s,e)}if(t)throw new Error("taskFunctions parameter object is empty")}}}hasTaskFunction(e){if("string"!=typeof e)throw new TypeError("name parameter is not a string");if("string"==typeof e&&0===e.trim().length)throw new TypeError("name parameter is an empty string");return this.taskFunctions.has(e)}addTaskFunction(e,t){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");if(e===w)throw new Error("Cannot add a task function with the default reserved name");if("function"!=typeof t)throw new TypeError("fn parameter is not a function");try{const s=t.bind(this);return this.taskFunctions.get(e)===this.taskFunctions.get(w)&&this.taskFunctions.set(w,s),this.taskFunctions.set(e,s),this.sendTaskFunctionsListToMainWorker(),!0}catch{return!1}}removeTaskFunction(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");if(e===w)throw new Error("Cannot remove the task function with the default reserved name");if(this.taskFunctions.get(e)===this.taskFunctions.get(w))throw new Error("Cannot remove the task function used as the default task function");const t=this.taskFunctions.delete(e);return this.sendTaskFunctionsListToMainWorker(),t}listTaskFunctions(){return[...this.taskFunctions.keys()]}setDefaultTaskFunction(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");if(e===w)throw new Error("Cannot set the default task function reserved name as the default task function");if(!this.taskFunctions.has(e))throw new Error("Cannot set the default task function to a non-existing task function");try{return this.taskFunctions.set(w,this.taskFunctions.get(e)),!0}catch{return!1}}messageListener(e){if(this.isMain)throw new Error("Cannot handle message to worker in main worker");if(null!=e.workerId&&e.workerId!==this.id)throw new Error(`Message worker id ${e.workerId} does not match the worker id ${this.id}`);e.workerId===this.id&&(null!=e.statistics?this.statistics=e.statistics:null!=e.checkActive?e.checkActive?this.startCheckActive():this.stopCheckActive():null!=e.taskId&&null!=e.data?this.run(e):!0===e.kill&&this.handleKillMessage(e))}handleKillMessage(e){if(this.stopCheckActive(),I(this.opts.killHandler))(this.opts.killHandler?.()).then((()=>(this.sendToMainWorker({kill:"success",workerId:this.id}),null))).catch((()=>{this.sendToMainWorker({kill:"failure",workerId:this.id})})).finally((()=>{this.emitDestroy()})).catch(y);else try{this.opts.killHandler?.(),this.sendToMainWorker({kill:"success",workerId:this.id})}catch{this.sendToMainWorker({kill:"failure",workerId:this.id})}finally{this.emitDestroy()}}startCheckActive(){this.lastTaskTimestamp=u.now(),this.activeInterval=setInterval(this.checkActive.bind(this),(this.opts.maxInactiveTime??G)/2)}stopCheckActive(){null!=this.activeInterval&&(clearInterval(this.activeInterval),delete this.activeInterval)}checkActive(){u.now()-this.lastTaskTimestamp>(this.opts.maxInactiveTime??G)&&this.sendToMainWorker({kill:this.opts.killBehavior,workerId:this.id})}getMainWorker(){if(null==this.mainWorker)throw new Error("Main worker not set");return this.mainWorker}sendTaskFunctionsListToMainWorker(){this.sendToMainWorker({taskFunctions:this.listTaskFunctions(),workerId:this.id})}handleError(e){return e instanceof Error?e.message:e}run(e){const t=this.getTaskFunction(e.name);I(t)?this.runInAsyncScope(this.runAsync.bind(this),this,t,e):this.runInAsyncScope(this.runSync.bind(this),this,t,e)}runSync(e,t){try{let s=this.beginTaskPerformance(t.name);const r=e(t.data);s=this.endTaskPerformance(s),this.sendToMainWorker({data:r,taskPerformance:s,workerId:this.id,taskId:t.taskId})}catch(e){const s=this.handleError(e);this.sendToMainWorker({taskError:{name:t.name??w,message:s,data:t.data},workerId:this.id,taskId:t.taskId})}finally{this.updateLastTaskTimestamp()}}runAsync(e,t){let s=this.beginTaskPerformance(t.name);e(t.data).then((e=>(s=this.endTaskPerformance(s),this.sendToMainWorker({data:e,taskPerformance:s,workerId:this.id,taskId:t.taskId}),null))).catch((e=>{const s=this.handleError(e);this.sendToMainWorker({taskError:{name:t.name??w,message:s,data:t.data},workerId:this.id,taskId:t.taskId})})).finally((()=>{this.updateLastTaskTimestamp()})).catch(y)}getTaskFunction(e){e=e??w;const t=this.taskFunctions.get(e);if(null==t)throw new Error(`Task function '${e}' not found`);return t}beginTaskPerformance(e){return this.checkStatistics(),{name:e??w,timestamp:u.now(),...this.statistics.elu&&{elu:u.eventLoopUtilization()}}}endTaskPerformance(e){return this.checkStatistics(),{...e,...this.statistics.runTime&&{runTime:u.now()-e.timestamp},...this.statistics.elu&&{elu:u.eventLoopUtilization(e.elu)}}}checkStatistics(){if(null==this.statistics)throw new Error("Performance statistics computation requirements not set")}updateLastTaskTimestamp(){null!=this.activeInterval&&(this.lastTaskTimestamp=u.now())}}class X extends J{constructor(e,t={}){super("worker-cluster-pool:poolifier",a.isPrimary,a.worker,e,t)}handleReadyMessage(e){e.workerId===this.id&&null!=e.ready&&(this.getMainWorker()?.on("message",this.messageListener.bind(this)),this.sendTaskFunctionsListToMainWorker(),this.sendToMainWorker({ready:!0,workerId:this.id}))}get id(){return this.getMainWorker().id}sendToMainWorker(e){this.getMainWorker().send(e)}}class Z extends J{port;constructor(e,t={}){super("worker-thread-pool:poolifier",s,o,e,t)}handleReadyMessage(e){e.workerId===this.id&&null!=e.ready&&null!=e.port&&(this.port=e.port,this.port.on("message",this.messageListener.bind(this)),this.sendTaskFunctionsListToMainWorker(),this.sendToMainWorker({ready:!0,workerId:this.id}))}handleKillMessage(e){super.handleKillMessage(e),this.port?.unref(),this.port?.close()}get id(){return n}sendToMainWorker(e){this.port.postMessage(e)}handleError(e){return e}}export{X as ClusterWorker,H as DynamicClusterPool,$ as DynamicThreadPool,V as FixedClusterPool,j as FixedThreadPool,R as KillBehaviors,v as Measurements,p as PoolEvents,m as PoolTypes,Z as ThreadWorker,C as WorkerChoiceStrategies,L as WorkerTypes,W as availableParallelism};
|
|
@@ -41,6 +41,10 @@ export declare abstract class AbstractPool<Worker extends IWorker, Data = unknow
|
|
|
41
41
|
* The start timestamp of the pool.
|
|
42
42
|
*/
|
|
43
43
|
private readonly startTimestamp;
|
|
44
|
+
/**
|
|
45
|
+
* The task function names.
|
|
46
|
+
*/
|
|
47
|
+
private taskFunctions;
|
|
44
48
|
/**
|
|
45
49
|
* Constructs a new poolifier pool.
|
|
46
50
|
*
|
|
@@ -136,9 +140,12 @@ export declare abstract class AbstractPool<Worker extends IWorker, Data = unknow
|
|
|
136
140
|
*/
|
|
137
141
|
protected internalBusy(): boolean;
|
|
138
142
|
/** @inheritDoc */
|
|
143
|
+
listTaskFunctions(): string[];
|
|
144
|
+
/** @inheritDoc */
|
|
139
145
|
execute(data?: Data, name?: string, transferList?: TransferListItem[]): Promise<Response>;
|
|
140
146
|
/** @inheritDoc */
|
|
141
147
|
destroy(): Promise<void>;
|
|
148
|
+
protected sendKillMessageToWorker(workerNodeKey: number, workerId: number): Promise<void>;
|
|
142
149
|
/**
|
|
143
150
|
* Terminates the worker node given its worker node key.
|
|
144
151
|
*
|
|
@@ -237,11 +244,11 @@ export declare abstract class AbstractPool<Worker extends IWorker, Data = unknow
|
|
|
237
244
|
*/
|
|
238
245
|
protected abstract sendStartupMessageToWorker(workerNodeKey: number): void;
|
|
239
246
|
/**
|
|
240
|
-
* Sends the
|
|
247
|
+
* Sends the statistics message to worker given its worker node key.
|
|
241
248
|
*
|
|
242
249
|
* @param workerNodeKey - The worker node key.
|
|
243
250
|
*/
|
|
244
|
-
private
|
|
251
|
+
private sendStatisticsMessageToWorker;
|
|
245
252
|
private redistributeQueuedTasks;
|
|
246
253
|
/**
|
|
247
254
|
* This method is the listener registered for each worker message.
|
package/lib/pools/pool.d.ts
CHANGED
|
@@ -182,6 +182,12 @@ export interface IPool<Worker extends IWorker, Data = unknown, Response = unknow
|
|
|
182
182
|
* Terminates all workers in this pool.
|
|
183
183
|
*/
|
|
184
184
|
readonly destroy: () => Promise<void>;
|
|
185
|
+
/**
|
|
186
|
+
* Lists the names of task function available in this pool.
|
|
187
|
+
*
|
|
188
|
+
* @returns The names of task function available in this pool.
|
|
189
|
+
*/
|
|
190
|
+
readonly listTaskFunctions: () => string[];
|
|
185
191
|
/**
|
|
186
192
|
* Sets the worker choice strategy in this pool.
|
|
187
193
|
*
|
package/lib/pools/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "2.6.
|
|
1
|
+
export declare const version = "2.6.26";
|
package/lib/utility-types.d.ts
CHANGED
|
@@ -97,7 +97,7 @@ export interface MessageValue<Data = unknown, ErrorData = unknown> extends Task<
|
|
|
97
97
|
/**
|
|
98
98
|
* Kill code.
|
|
99
99
|
*/
|
|
100
|
-
readonly kill?: KillBehavior | true;
|
|
100
|
+
readonly kill?: KillBehavior | true | 'success' | 'failure';
|
|
101
101
|
/**
|
|
102
102
|
* Task error.
|
|
103
103
|
*/
|
|
@@ -106,6 +106,10 @@ export interface MessageValue<Data = unknown, ErrorData = unknown> extends Task<
|
|
|
106
106
|
* Task performance.
|
|
107
107
|
*/
|
|
108
108
|
readonly taskPerformance?: TaskPerformance;
|
|
109
|
+
/**
|
|
110
|
+
* Task function names.
|
|
111
|
+
*/
|
|
112
|
+
readonly taskFunctions?: string[];
|
|
109
113
|
/**
|
|
110
114
|
* Whether the worker computes the given statistics or not.
|
|
111
115
|
*/
|
|
@@ -144,6 +144,10 @@ export declare abstract class AbstractWorker<MainWorker extends Worker | Message
|
|
|
144
144
|
* @param message - The response message.
|
|
145
145
|
*/
|
|
146
146
|
protected abstract sendToMainWorker(message: MessageValue<Response, Data>): void;
|
|
147
|
+
/**
|
|
148
|
+
* Sends the list of task function names to the main worker.
|
|
149
|
+
*/
|
|
150
|
+
protected sendTaskFunctionsListToMainWorker(): void;
|
|
147
151
|
/**
|
|
148
152
|
* Handles an error and convert it to a string so it can be sent back to the main worker.
|
|
149
153
|
*
|
|
@@ -15,6 +15,10 @@ export declare const KillBehaviors: Readonly<{
|
|
|
15
15
|
* Kill behavior.
|
|
16
16
|
*/
|
|
17
17
|
export type KillBehavior = keyof typeof KillBehaviors;
|
|
18
|
+
/**
|
|
19
|
+
* Handler called when a worker is killed.
|
|
20
|
+
*/
|
|
21
|
+
export type KillHandler = () => void | Promise<void>;
|
|
18
22
|
/**
|
|
19
23
|
* Options for workers.
|
|
20
24
|
*/
|
|
@@ -50,4 +54,8 @@ export interface WorkerOptions {
|
|
|
50
54
|
* @defaultValue KillBehaviors.SOFT
|
|
51
55
|
*/
|
|
52
56
|
killBehavior?: KillBehavior;
|
|
57
|
+
/**
|
|
58
|
+
* The function to call when a worker is killed.
|
|
59
|
+
*/
|
|
60
|
+
killHandler?: KillHandler;
|
|
53
61
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "poolifier",
|
|
4
|
-
"version": "2.6.
|
|
4
|
+
"version": "2.6.26",
|
|
5
5
|
"description": "Fast and small Node.js Worker_Threads and Cluster Worker Pool",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "./lib/index.js",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"@release-it/keep-a-changelog": "^4.0.0",
|
|
86
86
|
"@rollup/plugin-terser": "^0.4.3",
|
|
87
87
|
"@rollup/plugin-typescript": "^11.1.2",
|
|
88
|
-
"@types/node": "^20.
|
|
88
|
+
"@types/node": "^20.5.0",
|
|
89
89
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
|
90
90
|
"@typescript-eslint/parser": "^5.62.0",
|
|
91
91
|
"benny": "^3.7.1",
|
|
@@ -103,16 +103,17 @@
|
|
|
103
103
|
"eslint-plugin-tsdoc": "^0.2.17",
|
|
104
104
|
"expect": "^29.6.2",
|
|
105
105
|
"husky": "^8.0.3",
|
|
106
|
-
"lint-staged": "^
|
|
106
|
+
"lint-staged": "^14.0.0",
|
|
107
107
|
"microtime": "^3.1.1",
|
|
108
108
|
"mocha": "^10.2.0",
|
|
109
109
|
"mochawesome": "^7.1.3",
|
|
110
110
|
"prettier": "^3.0.1",
|
|
111
|
-
"release-it": "^16.1.
|
|
111
|
+
"release-it": "^16.1.5",
|
|
112
112
|
"rollup": "^3.28.0",
|
|
113
113
|
"rollup-plugin-analyzer": "^4.0.0",
|
|
114
114
|
"rollup-plugin-command": "^1.1.3",
|
|
115
115
|
"rollup-plugin-delete": "^2.0.0",
|
|
116
|
+
"rome": "^12.1.3",
|
|
116
117
|
"sinon": "^15.2.0",
|
|
117
118
|
"source-map-support": "^0.5.21",
|
|
118
119
|
"ts-standard": "^12.0.2",
|
|
@@ -132,7 +133,7 @@
|
|
|
132
133
|
"test:debug": "pnpm build && mocha --no-parallel --inspect 'tests/**/*.test.js'",
|
|
133
134
|
"coverage": "c8 report --reporter=lcov",
|
|
134
135
|
"coverage:html": "c8 report --reporter=html",
|
|
135
|
-
"format": "
|
|
136
|
+
"format": "rome format . --write; ts-standard . --fix",
|
|
136
137
|
"lint": "eslint . --cache",
|
|
137
138
|
"lint:fix": "eslint . --cache --fix",
|
|
138
139
|
"lint:report": "eslint . --cache --format json --output-file reports/eslint.json",
|