fix: fix worker choice strategies behavior
[poolifier.git] / src / pools / selection-strategies / abstract-worker-choice-strategy.ts
CommitLineData
e9ed6eee 1import type { IPool } from '../pool.js'
bcfb06ce 2import { DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS } from '../utils.js'
d35e5717 3import type { IWorker } from '../worker.js'
10fcfaf4
JB
4import type {
5 IWorkerChoiceStrategy,
6c6afb84 6 StrategyPolicy,
39618ede
JB
7 TaskStatisticsRequirements,
8 WorkerChoiceStrategyOptions
d35e5717 9} from './selection-strategies-types.js'
763abb1c
JB
10import {
11 buildWorkerChoiceStrategyOptions,
12 toggleMedianMeasurementStatisticsRequirements
13} from './selection-strategies-utils.js'
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 */
b1aae695 30 protected nextWorkerNodeKey: number | undefined = 0
d33be430 31
7c7bb289
JB
32 /**
33 * The previous worker node key.
34 */
c63a35a0 35 protected previousWorkerNodeKey = 0
7c7bb289 36
6c6afb84
JB
37 /** @inheritDoc */
38 public readonly strategyPolicy: StrategyPolicy = {
b1aae695 39 dynamicWorkerUsage: false,
f6bc9f26 40 dynamicWorkerReady: true
6c6afb84
JB
41 }
42
afc003b2 43 /** @inheritDoc */
87de9ff5 44 public readonly taskStatisticsRequirements: TaskStatisticsRequirements = {
3c93feb9
JB
45 runTime: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS,
46 waitTime: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS,
47 elu: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS
10fcfaf4 48 }
bdaf31cd
JB
49
50 /**
6533c3e6 51 * Constructs a worker choice strategy bound to the pool.
bdaf31cd 52 *
38e795c1 53 * @param pool - The pool instance.
da309861 54 * @param opts - The worker choice strategy options.
bdaf31cd
JB
55 */
56 public constructor (
c4855468 57 protected readonly pool: IPool<Worker, Data, Response>,
39618ede 58 protected opts?: WorkerChoiceStrategyOptions
b8f3418c 59 ) {
7254e419 60 this.choose = this.choose.bind(this)
04d875a3 61 this.setOptions(this.opts)
b8f3418c 62 }
bdaf31cd 63
932fc8be 64 protected setTaskStatisticsRequirements (
39618ede 65 opts: WorkerChoiceStrategyOptions | undefined
932fc8be 66 ): void {
763abb1c 67 toggleMedianMeasurementStatisticsRequirements(
57441b79 68 this.taskStatisticsRequirements.runTime,
67f3f2d6 69 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
39618ede 70 opts!.runTime!.median
57441b79 71 )
763abb1c 72 toggleMedianMeasurementStatisticsRequirements(
57441b79 73 this.taskStatisticsRequirements.waitTime,
67f3f2d6 74 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
39618ede 75 opts!.waitTime!.median
57441b79 76 )
763abb1c 77 toggleMedianMeasurementStatisticsRequirements(
57441b79 78 this.taskStatisticsRequirements.elu,
67f3f2d6 79 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
39618ede 80 opts!.elu!.median
57441b79
JB
81 )
82 }
83
39a43af7
JB
84 protected resetWorkerNodeKeyProperties (): void {
85 this.nextWorkerNodeKey = 0
86 this.previousWorkerNodeKey = 0
87 }
88
afc003b2 89 /** @inheritDoc */
a6f7f1b4 90 public abstract reset (): boolean
ea7a90d3 91
138d29a8 92 /** @inheritDoc */
a4958de2 93 public abstract update (workerNodeKey: number): boolean
138d29a8 94
afc003b2 95 /** @inheritDoc */
b1aae695 96 public abstract choose (): number | undefined
97a2abc3 97
afc003b2 98 /** @inheritDoc */
f06e48d8 99 public abstract remove (workerNodeKey: number): boolean
a20f0ba5
JB
100
101 /** @inheritDoc */
39618ede
JB
102 public setOptions (opts: WorkerChoiceStrategyOptions | undefined): void {
103 this.opts = buildWorkerChoiceStrategyOptions<Worker, Data, Response>(
104 this.pool,
00e1bdeb
JB
105 opts
106 )
65ab8dcc 107 this.setTaskStatisticsRequirements(this.opts)
a20f0ba5 108 }
cb70b19d 109
d4ddb68b
JB
110 /**
111 * Whether the worker node is ready or not.
112 *
113 * @param workerNodeKey - The worker node key.
114 * @returns Whether the worker node is ready or not.
115 */
ae3ab61d 116 protected isWorkerNodeReady (workerNodeKey: number): boolean {
535fd8d5 117 return this.pool.workerNodes[workerNodeKey]?.info?.ready ?? false
19dbc45b
JB
118 }
119
a38b62f1 120 /**
8e8d9101 121 * Check the next worker node key.
a38b62f1 122 */
8e8d9101
JB
123 protected checkNextWorkerNodeKey (): void {
124 if (
125 this.nextWorkerNodeKey != null &&
126 (this.nextWorkerNodeKey < 0 ||
127 !this.isWorkerNodeReady(this.nextWorkerNodeKey))
128 ) {
a38b62f1
JB
129 delete this.nextWorkerNodeKey
130 }
131 }
132
f6b641d6 133 /**
f3a91bac 134 * Gets the worker node task runtime.
932fc8be 135 * If the task statistics require the average runtime, the average runtime is returned.
e0843544 136 * If the task statistics require the median runtime, the median runtime is returned.
f6b641d6
JB
137 *
138 * @param workerNodeKey - The worker node key.
f3a91bac 139 * @returns The worker node task runtime.
f6b641d6 140 */
f3a91bac 141 protected getWorkerNodeTaskRunTime (workerNodeKey: number): number {
932fc8be 142 return this.taskStatisticsRequirements.runTime.median
46b0bb09
JB
143 ? this.pool.workerNodes[workerNodeKey].usage.runTime.median ?? 0
144 : this.pool.workerNodes[workerNodeKey].usage.runTime.average ?? 0
f6b641d6
JB
145 }
146
ef680bb8 147 /**
f3a91bac 148 * Gets the worker node task wait time.
932fc8be
JB
149 * If the task statistics require the average wait time, the average wait time is returned.
150 * If the task statistics require the median wait time, the median wait time is returned.
ef680bb8
JB
151 *
152 * @param workerNodeKey - The worker node key.
f3a91bac 153 * @returns The worker node task wait time.
ef680bb8 154 */
f3a91bac 155 protected getWorkerNodeTaskWaitTime (workerNodeKey: number): number {
932fc8be 156 return this.taskStatisticsRequirements.waitTime.median
46b0bb09
JB
157 ? this.pool.workerNodes[workerNodeKey].usage.waitTime.median ?? 0
158 : this.pool.workerNodes[workerNodeKey].usage.waitTime.average ?? 0
ef680bb8
JB
159 }
160
5df69fab 161 /**
f3a91bac 162 * Gets the worker node task ELU.
9adcefab
JB
163 * If the task statistics require the average ELU, the average ELU is returned.
164 * If the task statistics require the median ELU, the median ELU is returned.
5df69fab
JB
165 *
166 * @param workerNodeKey - The worker node key.
f3a91bac 167 * @returns The worker node task ELU.
5df69fab 168 */
f3a91bac 169 protected getWorkerNodeTaskElu (workerNodeKey: number): number {
5df69fab 170 return this.taskStatisticsRequirements.elu.median
46b0bb09
JB
171 ? this.pool.workerNodes[workerNodeKey].usage.elu.active.median ?? 0
172 : this.pool.workerNodes[workerNodeKey].usage.elu.active.average ?? 0
5df69fab
JB
173 }
174
baca80f7
JB
175 /**
176 * Sets safely the previous worker node key.
177 *
178 * @param workerNodeKey - The worker node key.
179 */
180 protected setPreviousWorkerNodeKey (workerNodeKey: number | undefined): void {
8e8d9101
JB
181 this.previousWorkerNodeKey =
182 workerNodeKey != null && workerNodeKey >= 0
183 ? workerNodeKey
184 : this.previousWorkerNodeKey
baca80f7 185 }
bdaf31cd 186}