fix: properly account worker choice retries for WRR
[poolifier.git] / src / pools / selection-strategies / abstract-worker-choice-strategy.ts
CommitLineData
3c93feb9
JB
1import {
2 DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS,
00e1bdeb 3 buildInternalWorkerChoiceStrategyOptions
3c93feb9 4} from '../../utils'
08f3f44c 5import type { IPool } from '../pool'
f06e48d8 6import type { IWorker } from '../worker'
10fcfaf4
JB
7import type {
8 IWorkerChoiceStrategy,
26ce26ca 9 InternalWorkerChoiceStrategyOptions,
57441b79 10 MeasurementStatisticsRequirements,
6c6afb84 11 StrategyPolicy,
26ce26ca 12 TaskStatisticsRequirements
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 */
b1aae695 30 protected nextWorkerNodeKey: number | undefined = 0
d33be430 31
7c7bb289
JB
32 /**
33 * The previous worker node key.
34 */
35 protected previousWorkerNodeKey: number = 0
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>,
26ce26ca 58 protected opts: InternalWorkerChoiceStrategyOptions
b8f3418c 59 ) {
26ce26ca 60 this.setOptions(this.opts)
7254e419 61 this.choose = this.choose.bind(this)
b8f3418c 62 }
bdaf31cd 63
932fc8be 64 protected setTaskStatisticsRequirements (
26ce26ca 65 opts: InternalWorkerChoiceStrategyOptions
932fc8be 66 ): void {
57441b79
JB
67 this.toggleMedianMeasurementStatisticsRequirements(
68 this.taskStatisticsRequirements.runTime,
69 opts.runTime?.median as boolean
70 )
71 this.toggleMedianMeasurementStatisticsRequirements(
72 this.taskStatisticsRequirements.waitTime,
73 opts.waitTime?.median as boolean
74 )
75 this.toggleMedianMeasurementStatisticsRequirements(
76 this.taskStatisticsRequirements.elu,
77 opts.elu?.median as boolean
78 )
79 }
80
81 private toggleMedianMeasurementStatisticsRequirements (
82 measurementStatisticsRequirements: MeasurementStatisticsRequirements,
83 toggleMedian: boolean
84 ): void {
85 if (measurementStatisticsRequirements.average && toggleMedian) {
86 measurementStatisticsRequirements.average = false
87 measurementStatisticsRequirements.median = toggleMedian
5df69fab 88 }
57441b79
JB
89 if (measurementStatisticsRequirements.median && !toggleMedian) {
90 measurementStatisticsRequirements.average = true
91 measurementStatisticsRequirements.median = toggleMedian
5df69fab 92 }
da309861
JB
93 }
94
39a43af7
JB
95 protected resetWorkerNodeKeyProperties (): void {
96 this.nextWorkerNodeKey = 0
97 this.previousWorkerNodeKey = 0
98 }
99
afc003b2 100 /** @inheritDoc */
a6f7f1b4 101 public abstract reset (): boolean
ea7a90d3 102
138d29a8 103 /** @inheritDoc */
a4958de2 104 public abstract update (workerNodeKey: number): boolean
138d29a8 105
afc003b2 106 /** @inheritDoc */
b1aae695 107 public abstract choose (): number | undefined
97a2abc3 108
afc003b2 109 /** @inheritDoc */
f06e48d8 110 public abstract remove (workerNodeKey: number): boolean
a20f0ba5
JB
111
112 /** @inheritDoc */
26ce26ca 113 public setOptions (opts: InternalWorkerChoiceStrategyOptions): void {
00e1bdeb
JB
114 this.opts = buildInternalWorkerChoiceStrategyOptions(
115 this.pool.info.maxSize,
116 opts
117 )
65ab8dcc 118 this.setTaskStatisticsRequirements(this.opts)
a20f0ba5 119 }
cb70b19d 120
fb5a7307
JB
121 /** @inheritDoc */
122 public hasPoolWorkerNodesReady (): boolean {
123 return this.pool.workerNodes.some(workerNode => workerNode.info.ready)
124 }
125
d4ddb68b
JB
126 /**
127 * Whether the worker node is ready or not.
128 *
129 * @param workerNodeKey - The worker node key.
130 * @returns Whether the worker node is ready or not.
131 */
ae3ab61d 132 protected isWorkerNodeReady (workerNodeKey: number): boolean {
535fd8d5 133 return this.pool.workerNodes[workerNodeKey]?.info?.ready ?? false
19dbc45b
JB
134 }
135
a38b62f1
JB
136 /**
137 * Check the next worker node readiness.
138 */
139 protected checkNextWorkerNodeReadiness (): void {
140 if (!this.isWorkerNodeReady(this.nextWorkerNodeKey as number)) {
141 delete this.nextWorkerNodeKey
142 }
143 }
144
f6b641d6 145 /**
f3a91bac 146 * Gets the worker node task runtime.
932fc8be
JB
147 * If the task statistics require the average runtime, the average runtime is returned.
148 * If the task statistics require the median runtime , the median runtime is returned.
f6b641d6
JB
149 *
150 * @param workerNodeKey - The worker node key.
f3a91bac 151 * @returns The worker node task runtime.
f6b641d6 152 */
f3a91bac 153 protected getWorkerNodeTaskRunTime (workerNodeKey: number): number {
932fc8be 154 return this.taskStatisticsRequirements.runTime.median
46b0bb09
JB
155 ? this.pool.workerNodes[workerNodeKey].usage.runTime.median ?? 0
156 : this.pool.workerNodes[workerNodeKey].usage.runTime.average ?? 0
f6b641d6
JB
157 }
158
ef680bb8 159 /**
f3a91bac 160 * Gets the worker node task wait time.
932fc8be
JB
161 * If the task statistics require the average wait time, the average wait time is returned.
162 * If the task statistics require the median wait time, the median wait time is returned.
ef680bb8
JB
163 *
164 * @param workerNodeKey - The worker node key.
f3a91bac 165 * @returns The worker node task wait time.
ef680bb8 166 */
f3a91bac 167 protected getWorkerNodeTaskWaitTime (workerNodeKey: number): number {
932fc8be 168 return this.taskStatisticsRequirements.waitTime.median
46b0bb09
JB
169 ? this.pool.workerNodes[workerNodeKey].usage.waitTime.median ?? 0
170 : this.pool.workerNodes[workerNodeKey].usage.waitTime.average ?? 0
ef680bb8
JB
171 }
172
5df69fab 173 /**
f3a91bac 174 * Gets the worker node task ELU.
9adcefab
JB
175 * If the task statistics require the average ELU, the average ELU is returned.
176 * If the task statistics require the median ELU, the median ELU is returned.
5df69fab
JB
177 *
178 * @param workerNodeKey - The worker node key.
f3a91bac 179 * @returns The worker node task ELU.
5df69fab 180 */
f3a91bac 181 protected getWorkerNodeTaskElu (workerNodeKey: number): number {
5df69fab 182 return this.taskStatisticsRequirements.elu.median
46b0bb09
JB
183 ? this.pool.workerNodes[workerNodeKey].usage.elu.active.median ?? 0
184 : this.pool.workerNodes[workerNodeKey].usage.elu.active.average ?? 0
5df69fab
JB
185 }
186
baca80f7
JB
187 /**
188 * Sets safely the previous worker node key.
189 *
190 * @param workerNodeKey - The worker node key.
191 */
192 protected setPreviousWorkerNodeKey (workerNodeKey: number | undefined): void {
193 this.previousWorkerNodeKey = workerNodeKey ?? this.previousWorkerNodeKey
194 }
bdaf31cd 195}