1 import { cpus
} from
'node:os'
3 DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS
,
4 DEFAULT_WORKER_CHOICE_STRATEGY_OPTIONS
6 import type { IPool
} from
'../pool'
7 import type { IWorker
} from
'../worker'
11 TaskStatisticsRequirements
,
12 WorkerChoiceStrategyOptions
13 } from
'./selection-strategies-types'
16 * Worker choice strategy abstract base class.
18 * @typeParam Worker - Type of worker which manages the strategy.
19 * @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
20 * @typeParam Response - Type of execution response. This can only be structured-cloneable data.
22 export abstract class AbstractWorkerChoiceStrategy
<
23 Worker
extends IWorker
,
26 > implements IWorkerChoiceStrategy
{
28 * The next worker node key.
30 protected nextWorkerNodeKey
: number = 0
33 public readonly strategyPolicy
: StrategyPolicy
= {
34 useDynamicWorker
: false
38 public readonly taskStatisticsRequirements
: TaskStatisticsRequirements
= {
39 runTime
: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS
,
40 waitTime
: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS
,
41 elu
: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS
45 * Constructs a worker choice strategy bound to the pool.
47 * @param pool - The pool instance.
48 * @param opts - The worker choice strategy options.
51 protected readonly pool
: IPool
<Worker
, Data
, Response
>,
52 protected opts
: WorkerChoiceStrategyOptions
= DEFAULT_WORKER_CHOICE_STRATEGY_OPTIONS
54 this.choose
= this.choose
.bind(this)
57 protected setTaskStatisticsRequirements (
58 opts
: WorkerChoiceStrategyOptions
61 this.taskStatisticsRequirements
.runTime
.average
&&
62 opts
.runTime
?.median
=== true
64 this.taskStatisticsRequirements
.runTime
.average
= false
65 this.taskStatisticsRequirements
.runTime
.median
= opts
.runTime
69 this.taskStatisticsRequirements
.runTime
.median
&&
70 opts
.runTime
?.median
=== false
72 this.taskStatisticsRequirements
.runTime
.average
= true
73 this.taskStatisticsRequirements
.runTime
.median
= opts
.runTime
77 this.taskStatisticsRequirements
.waitTime
.average
&&
78 opts
.waitTime
?.median
=== true
80 this.taskStatisticsRequirements
.waitTime
.average
= false
81 this.taskStatisticsRequirements
.waitTime
.median
= opts
.waitTime
85 this.taskStatisticsRequirements
.waitTime
.median
&&
86 opts
.waitTime
?.median
=== false
88 this.taskStatisticsRequirements
.waitTime
.average
= true
89 this.taskStatisticsRequirements
.waitTime
.median
= opts
.waitTime
93 this.taskStatisticsRequirements
.elu
.average
&&
94 opts
.elu
?.median
=== true
96 this.taskStatisticsRequirements
.elu
.average
= false
97 this.taskStatisticsRequirements
.elu
.median
= opts
.elu
.median
as boolean
100 this.taskStatisticsRequirements
.elu
.median
&&
101 opts
.elu
?.median
=== false
103 this.taskStatisticsRequirements
.elu
.average
= true
104 this.taskStatisticsRequirements
.elu
.median
= opts
.elu
.median
as boolean
109 public abstract reset (): boolean
112 public abstract update (workerNodeKey
: number): boolean
115 public abstract choose (): number
118 public abstract remove (workerNodeKey
: number): boolean
121 public setOptions (opts
: WorkerChoiceStrategyOptions
): void {
122 this.opts
= opts
?? DEFAULT_WORKER_CHOICE_STRATEGY_OPTIONS
123 this.setTaskStatisticsRequirements(this.opts
)
126 protected isWorkerNodeReady (workerNodeKey
: number): boolean {
127 return this.pool
.workerNodes
[workerNodeKey
].info
.ready
131 * Gets the worker task runtime.
132 * If the task statistics require the average runtime, the average runtime is returned.
133 * If the task statistics require the median runtime , the median runtime is returned.
135 * @param workerNodeKey - The worker node key.
136 * @returns The worker task runtime.
138 protected getWorkerTaskRunTime (workerNodeKey
: number): number {
139 return this.taskStatisticsRequirements
.runTime
.median
140 ? this.pool
.workerNodes
[workerNodeKey
].usage
.runTime
?.median
?? 0
141 : this.pool
.workerNodes
[workerNodeKey
].usage
.runTime
?.average
?? 0
145 * Gets the worker task wait time.
146 * If the task statistics require the average wait time, the average wait time is returned.
147 * If the task statistics require the median wait time, the median wait time is returned.
149 * @param workerNodeKey - The worker node key.
150 * @returns The worker task wait time.
152 protected getWorkerTaskWaitTime (workerNodeKey
: number): number {
153 return this.taskStatisticsRequirements
.waitTime
.median
154 ? this.pool
.workerNodes
[workerNodeKey
].usage
.waitTime
?.median
?? 0
155 : this.pool
.workerNodes
[workerNodeKey
].usage
.waitTime
?.average
?? 0
159 * Gets the worker task ELU.
160 * If the task statistics require the average ELU, the average ELU is returned.
161 * If the task statistics require the median ELU, the median ELU is returned.
163 * @param workerNodeKey - The worker node key.
164 * @returns The worker task ELU.
166 protected getWorkerTaskElu (workerNodeKey
: number): number {
167 return this.taskStatisticsRequirements
.elu
.median
168 ? this.pool
.workerNodes
[workerNodeKey
].usage
.elu
.active
?.median
?? 0
169 : this.pool
.workerNodes
[workerNodeKey
].usage
.elu
.active
?.average
?? 0
172 protected computeDefaultWorkerWeight (): number {
173 let cpusCycleTimeWeight
= 0
174 for (const cpu
of cpus()) {
175 // CPU estimated cycle time
176 const numberOfDigits
= cpu
.speed
.toString().length
- 1
177 const cpuCycleTime
= 1 / (cpu
.speed
/ Math.pow(10, numberOfDigits
))
178 cpusCycleTimeWeight
+= cpuCycleTime
* Math.pow(10, numberOfDigits
)
180 return Math.round(cpusCycleTimeWeight
/ cpus().length
)