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