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