fix: put back properties init in constructor
[poolifier.git] / src / pools / selection-strategies / abstract-worker-choice-strategy.ts
1 import {
2 DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS,
3 buildInternalWorkerChoiceStrategyOptions
4 } from '../../utils'
5 import type { IPool } from '../pool'
6 import type { IWorker } from '../worker'
7 import type {
8 IWorkerChoiceStrategy,
9 InternalWorkerChoiceStrategyOptions,
10 MeasurementStatisticsRequirements,
11 StrategyPolicy,
12 TaskStatisticsRequirements
13 } from './selection-strategies-types'
14
15 /**
16 * Worker choice strategy abstract base class.
17 *
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.
21 */
22 export abstract class AbstractWorkerChoiceStrategy<
23 Worker extends IWorker,
24 Data = unknown,
25 Response = unknown
26 > implements IWorkerChoiceStrategy {
27 /**
28 * The next worker node key.
29 */
30 protected nextWorkerNodeKey: number | undefined = 0
31
32 /**
33 * The previous worker node key.
34 */
35 protected previousWorkerNodeKey: number = 0
36
37 /** @inheritDoc */
38 public readonly strategyPolicy: StrategyPolicy = {
39 dynamicWorkerUsage: false,
40 dynamicWorkerReady: true
41 }
42
43 /** @inheritDoc */
44 public readonly taskStatisticsRequirements: TaskStatisticsRequirements = {
45 runTime: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS,
46 waitTime: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS,
47 elu: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS
48 }
49
50 /**
51 * Constructs a worker choice strategy bound to the pool.
52 *
53 * @param pool - The pool instance.
54 * @param opts - The worker choice strategy options.
55 */
56 public constructor (
57 protected readonly pool: IPool<Worker, Data, Response>,
58 protected opts: InternalWorkerChoiceStrategyOptions
59 ) {
60 // this.setOptions(this.opts)
61 this.opts = buildInternalWorkerChoiceStrategyOptions(
62 this.pool.info.maxSize,
63 this.opts
64 )
65 this.setTaskStatisticsRequirements(this.opts)
66 this.choose = this.choose.bind(this)
67 }
68
69 protected setTaskStatisticsRequirements (
70 opts: InternalWorkerChoiceStrategyOptions
71 ): void {
72 this.toggleMedianMeasurementStatisticsRequirements(
73 this.taskStatisticsRequirements.runTime,
74 opts.runTime?.median as boolean
75 )
76 this.toggleMedianMeasurementStatisticsRequirements(
77 this.taskStatisticsRequirements.waitTime,
78 opts.waitTime?.median as boolean
79 )
80 this.toggleMedianMeasurementStatisticsRequirements(
81 this.taskStatisticsRequirements.elu,
82 opts.elu?.median as boolean
83 )
84 }
85
86 private toggleMedianMeasurementStatisticsRequirements (
87 measurementStatisticsRequirements: MeasurementStatisticsRequirements,
88 toggleMedian: boolean
89 ): void {
90 if (measurementStatisticsRequirements.average && toggleMedian) {
91 measurementStatisticsRequirements.average = false
92 measurementStatisticsRequirements.median = toggleMedian
93 }
94 if (measurementStatisticsRequirements.median && !toggleMedian) {
95 measurementStatisticsRequirements.average = true
96 measurementStatisticsRequirements.median = toggleMedian
97 }
98 }
99
100 protected resetWorkerNodeKeyProperties (): void {
101 this.nextWorkerNodeKey = 0
102 this.previousWorkerNodeKey = 0
103 }
104
105 /** @inheritDoc */
106 public abstract reset (): boolean
107
108 /** @inheritDoc */
109 public abstract update (workerNodeKey: number): boolean
110
111 /** @inheritDoc */
112 public abstract choose (): number | undefined
113
114 /** @inheritDoc */
115 public abstract remove (workerNodeKey: number): boolean
116
117 /** @inheritDoc */
118 public setOptions (opts: InternalWorkerChoiceStrategyOptions): void {
119 this.opts = buildInternalWorkerChoiceStrategyOptions(
120 this.pool.info.maxSize,
121 opts
122 )
123 this.setTaskStatisticsRequirements(this.opts)
124 }
125
126 /** @inheritDoc */
127 public hasPoolWorkerNodesReady (): boolean {
128 return this.pool.workerNodes.some(workerNode => workerNode.info.ready)
129 }
130
131 /**
132 * Whether the worker node is ready or not.
133 *
134 * @param workerNodeKey - The worker node key.
135 * @returns Whether the worker node is ready or not.
136 */
137 protected isWorkerNodeReady (workerNodeKey: number): boolean {
138 return this.pool.workerNodes[workerNodeKey]?.info?.ready ?? false
139 }
140
141 /**
142 * Check the next worker node readiness.
143 */
144 protected checkNextWorkerNodeReadiness (): void {
145 if (!this.isWorkerNodeReady(this.nextWorkerNodeKey as number)) {
146 delete this.nextWorkerNodeKey
147 }
148 }
149
150 /**
151 * Gets the worker node task runtime.
152 * If the task statistics require the average runtime, the average runtime is returned.
153 * If the task statistics require the median runtime , the median runtime is returned.
154 *
155 * @param workerNodeKey - The worker node key.
156 * @returns The worker node task runtime.
157 */
158 protected getWorkerNodeTaskRunTime (workerNodeKey: number): number {
159 return this.taskStatisticsRequirements.runTime.median
160 ? this.pool.workerNodes[workerNodeKey].usage.runTime.median ?? 0
161 : this.pool.workerNodes[workerNodeKey].usage.runTime.average ?? 0
162 }
163
164 /**
165 * Gets the worker node task wait time.
166 * If the task statistics require the average wait time, the average wait time is returned.
167 * If the task statistics require the median wait time, the median wait time is returned.
168 *
169 * @param workerNodeKey - The worker node key.
170 * @returns The worker node task wait time.
171 */
172 protected getWorkerNodeTaskWaitTime (workerNodeKey: number): number {
173 return this.taskStatisticsRequirements.waitTime.median
174 ? this.pool.workerNodes[workerNodeKey].usage.waitTime.median ?? 0
175 : this.pool.workerNodes[workerNodeKey].usage.waitTime.average ?? 0
176 }
177
178 /**
179 * Gets the worker node task ELU.
180 * If the task statistics require the average ELU, the average ELU is returned.
181 * If the task statistics require the median ELU, the median ELU is returned.
182 *
183 * @param workerNodeKey - The worker node key.
184 * @returns The worker node task ELU.
185 */
186 protected getWorkerNodeTaskElu (workerNodeKey: number): number {
187 return this.taskStatisticsRequirements.elu.median
188 ? this.pool.workerNodes[workerNodeKey].usage.elu.active.median ?? 0
189 : this.pool.workerNodes[workerNodeKey].usage.elu.active.average ?? 0
190 }
191
192 /**
193 * Sets safely the previous worker node key.
194 *
195 * @param workerNodeKey - The worker node key.
196 */
197 protected setPreviousWorkerNodeKey (workerNodeKey: number | undefined): void {
198 this.previousWorkerNodeKey = workerNodeKey ?? this.previousWorkerNodeKey
199 }
200 }