docs: fix README.md
[poolifier.git] / src / pools / selection-strategies / abstract-worker-choice-strategy.ts
CommitLineData
0bbf65c3 1import { cpus } from 'node:os'
3c93feb9
JB
2import {
3 DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS,
4 DEFAULT_WORKER_CHOICE_STRATEGY_OPTIONS
5} from '../../utils'
08f3f44c 6import type { IPool } from '../pool'
f06e48d8 7import type { IWorker } from '../worker'
10fcfaf4
JB
8import type {
9 IWorkerChoiceStrategy,
6c6afb84 10 StrategyPolicy,
87de9ff5 11 TaskStatisticsRequirements,
da309861 12 WorkerChoiceStrategyOptions
10fcfaf4 13} from './selection-strategies-types'
bdaf31cd
JB
14
15/**
9cd39dd4 16 * Worker choice strategy abstract base class.
bdaf31cd 17 *
38e795c1 18 * @typeParam Worker - Type of worker which manages the strategy.
e102732c
JB
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.
bdaf31cd
JB
21 */
22export abstract class AbstractWorkerChoiceStrategy<
f06e48d8 23 Worker extends IWorker,
b2b1d84e
JB
24 Data = unknown,
25 Response = unknown
17393ac8 26> implements IWorkerChoiceStrategy {
d33be430 27 /**
9b106837 28 * The next worker node key.
d33be430 29 */
9b106837 30 protected nextWorkerNodeKey: number = 0
d33be430 31
6c6afb84
JB
32 /** @inheritDoc */
33 public readonly strategyPolicy: StrategyPolicy = {
34 useDynamicWorker: false
35 }
36
afc003b2 37 /** @inheritDoc */
87de9ff5 38 public readonly taskStatisticsRequirements: TaskStatisticsRequirements = {
3c93feb9
JB
39 runTime: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS,
40 waitTime: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS,
41 elu: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS
10fcfaf4 42 }
bdaf31cd
JB
43
44 /**
6533c3e6 45 * Constructs a worker choice strategy bound to the pool.
bdaf31cd 46 *
38e795c1 47 * @param pool - The pool instance.
da309861 48 * @param opts - The worker choice strategy options.
bdaf31cd
JB
49 */
50 public constructor (
c4855468 51 protected readonly pool: IPool<Worker, Data, Response>,
a20f0ba5 52 protected opts: WorkerChoiceStrategyOptions = DEFAULT_WORKER_CHOICE_STRATEGY_OPTIONS
b8f3418c 53 ) {
7254e419 54 this.choose = this.choose.bind(this)
b8f3418c 55 }
bdaf31cd 56
932fc8be
JB
57 protected setTaskStatisticsRequirements (
58 opts: WorkerChoiceStrategyOptions
59 ): void {
87de9ff5 60 if (
932fc8be
JB
61 this.taskStatisticsRequirements.runTime.average &&
62 opts.runTime?.median === true
87de9ff5 63 ) {
932fc8be
JB
64 this.taskStatisticsRequirements.runTime.average = false
65 this.taskStatisticsRequirements.runTime.median = opts.runTime
66 .median as boolean
da309861 67 }
87de9ff5 68 if (
932fc8be
JB
69 this.taskStatisticsRequirements.runTime.median &&
70 opts.runTime?.median === false
87de9ff5 71 ) {
932fc8be
JB
72 this.taskStatisticsRequirements.runTime.average = true
73 this.taskStatisticsRequirements.runTime.median = opts.runTime
74 .median as boolean
a20f0ba5 75 }
87de9ff5 76 if (
932fc8be
JB
77 this.taskStatisticsRequirements.waitTime.average &&
78 opts.waitTime?.median === true
87de9ff5 79 ) {
932fc8be
JB
80 this.taskStatisticsRequirements.waitTime.average = false
81 this.taskStatisticsRequirements.waitTime.median = opts.waitTime
82 .median as boolean
0567595a 83 }
87de9ff5 84 if (
932fc8be
JB
85 this.taskStatisticsRequirements.waitTime.median &&
86 opts.waitTime?.median === false
87de9ff5 87 ) {
932fc8be
JB
88 this.taskStatisticsRequirements.waitTime.average = true
89 this.taskStatisticsRequirements.waitTime.median = opts.waitTime
90 .median as boolean
0567595a 91 }
5df69fab
JB
92 if (
93 this.taskStatisticsRequirements.elu.average &&
94 opts.elu?.median === true
95 ) {
96 this.taskStatisticsRequirements.elu.average = false
97 this.taskStatisticsRequirements.elu.median = opts.elu.median as boolean
98 }
99 if (
100 this.taskStatisticsRequirements.elu.median &&
101 opts.elu?.median === false
102 ) {
103 this.taskStatisticsRequirements.elu.average = true
104 this.taskStatisticsRequirements.elu.median = opts.elu.median as boolean
105 }
da309861
JB
106 }
107
afc003b2 108 /** @inheritDoc */
a6f7f1b4 109 public abstract reset (): boolean
ea7a90d3 110
138d29a8 111 /** @inheritDoc */
a4958de2 112 public abstract update (workerNodeKey: number): boolean
138d29a8 113
afc003b2 114 /** @inheritDoc */
c923ce56 115 public abstract choose (): number
97a2abc3 116
afc003b2 117 /** @inheritDoc */
f06e48d8 118 public abstract remove (workerNodeKey: number): boolean
a20f0ba5
JB
119
120 /** @inheritDoc */
121 public setOptions (opts: WorkerChoiceStrategyOptions): void {
65ab8dcc
JB
122 this.opts = opts ?? DEFAULT_WORKER_CHOICE_STRATEGY_OPTIONS
123 this.setTaskStatisticsRequirements(this.opts)
a20f0ba5 124 }
cb70b19d 125
9b106837 126 protected isWorkerNodeReady (workerNodeKey: number): boolean {
19dbc45b
JB
127 return this.pool.workerNodes[workerNodeKey].info.ready
128 }
129
f6b641d6 130 /**
e6606302 131 * Gets the worker task runtime.
932fc8be
JB
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.
f6b641d6
JB
134 *
135 * @param workerNodeKey - The worker node key.
e6606302 136 * @returns The worker task runtime.
f6b641d6
JB
137 */
138 protected getWorkerTaskRunTime (workerNodeKey: number): number {
932fc8be 139 return this.taskStatisticsRequirements.runTime.median
71514351
JB
140 ? this.pool.workerNodes[workerNodeKey].usage.runTime?.median ?? 0
141 : this.pool.workerNodes[workerNodeKey].usage.runTime?.average ?? 0
f6b641d6
JB
142 }
143
ef680bb8
JB
144 /**
145 * Gets the worker task wait time.
932fc8be
JB
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.
ef680bb8
JB
148 *
149 * @param workerNodeKey - The worker node key.
150 * @returns The worker task wait time.
151 */
5df69fab 152 protected getWorkerTaskWaitTime (workerNodeKey: number): number {
932fc8be 153 return this.taskStatisticsRequirements.waitTime.median
71514351
JB
154 ? this.pool.workerNodes[workerNodeKey].usage.waitTime?.median ?? 0
155 : this.pool.workerNodes[workerNodeKey].usage.waitTime?.average ?? 0
ef680bb8
JB
156 }
157
5df69fab
JB
158 /**
159 * Gets the worker task ELU.
9adcefab
JB
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.
5df69fab
JB
162 *
163 * @param workerNodeKey - The worker node key.
164 * @returns The worker task ELU.
165 */
166 protected getWorkerTaskElu (workerNodeKey: number): number {
167 return this.taskStatisticsRequirements.elu.median
71514351
JB
168 ? this.pool.workerNodes[workerNodeKey].usage.elu.active?.median ?? 0
169 : this.pool.workerNodes[workerNodeKey].usage.elu.active?.average ?? 0
5df69fab
JB
170 }
171
0bbf65c3
JB
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)
179 }
180 return Math.round(cpusCycleTimeWeight / cpus().length)
181 }
bdaf31cd 182}