Merge branch 'elu-strategy' of github.com:poolifier/poolifier into elu-strategy
[poolifier.git] / src / pools / selection-strategies / worker-choice-strategy-context.ts
1 import { DEFAULT_WORKER_CHOICE_STRATEGY_OPTIONS } from '../../utils'
2 import type { IPool } from '../pool'
3 import type { IWorker } from '../worker'
4 import { FairShareWorkerChoiceStrategy } from './fair-share-worker-choice-strategy'
5 import { InterleavedWeightedRoundRobinWorkerChoiceStrategy } from './interleaved-weighted-round-robin-worker-choice-strategy'
6 import { LeastBusyWorkerChoiceStrategy } from './least-busy-worker-choice-strategy'
7 import { LeastUsedWorkerChoiceStrategy } from './least-used-worker-choice-strategy'
8 import { LeastEluWorkerChoiceStrategy } from './least-elu-worker-choice-strategy'
9 import { RoundRobinWorkerChoiceStrategy } from './round-robin-worker-choice-strategy'
10 import type {
11 IWorkerChoiceStrategy,
12 TaskStatisticsRequirements,
13 WorkerChoiceStrategy,
14 WorkerChoiceStrategyOptions
15 } from './selection-strategies-types'
16 import { WorkerChoiceStrategies } from './selection-strategies-types'
17 import { WeightedRoundRobinWorkerChoiceStrategy } from './weighted-round-robin-worker-choice-strategy'
18
19 /**
20 * The worker choice strategy context.
21 *
22 * @typeParam Worker - Type of worker.
23 * @typeParam Data - Type of data sent to the worker. This can only be serializable data.
24 * @typeParam Response - Type of execution response. This can only be serializable data.
25 */
26 export class WorkerChoiceStrategyContext<
27 Worker extends IWorker,
28 Data = unknown,
29 Response = unknown
30 > {
31 private readonly workerChoiceStrategies: Map<
32 WorkerChoiceStrategy,
33 IWorkerChoiceStrategy
34 >
35
36 /**
37 * Worker choice strategy context constructor.
38 *
39 * @param pool - The pool instance.
40 * @param workerChoiceStrategy - The worker choice strategy.
41 * @param opts - The worker choice strategy options.
42 */
43 public constructor (
44 pool: IPool<Worker, Data, Response>,
45 private workerChoiceStrategy: WorkerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN,
46 opts: WorkerChoiceStrategyOptions = DEFAULT_WORKER_CHOICE_STRATEGY_OPTIONS
47 ) {
48 this.execute = this.execute.bind(this)
49 this.workerChoiceStrategies = new Map<
50 WorkerChoiceStrategy,
51 IWorkerChoiceStrategy
52 >([
53 [
54 WorkerChoiceStrategies.ROUND_ROBIN,
55 new (RoundRobinWorkerChoiceStrategy.bind(this))<Worker, Data, Response>(
56 pool,
57 opts
58 )
59 ],
60 [
61 WorkerChoiceStrategies.LEAST_USED,
62 new (LeastUsedWorkerChoiceStrategy.bind(this))<Worker, Data, Response>(
63 pool,
64 opts
65 )
66 ],
67 [
68 WorkerChoiceStrategies.LEAST_BUSY,
69 new (LeastBusyWorkerChoiceStrategy.bind(this))<Worker, Data, Response>(
70 pool,
71 opts
72 )
73 ],
74 [
75 WorkerChoiceStrategies.LEAST_ELU,
76 new (LeastEluWorkerChoiceStrategy.bind(this))<Worker, Data, Response>(
77 pool,
78 opts
79 )
80 ],
81 [
82 WorkerChoiceStrategies.FAIR_SHARE,
83 new (FairShareWorkerChoiceStrategy.bind(this))<Worker, Data, Response>(
84 pool,
85 opts
86 )
87 ],
88 [
89 WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN,
90 new (WeightedRoundRobinWorkerChoiceStrategy.bind(this))<
91 Worker,
92 Data,
93 Response
94 >(pool, opts)
95 ],
96 [
97 WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN,
98 new (InterleavedWeightedRoundRobinWorkerChoiceStrategy.bind(this))<
99 Worker,
100 Data,
101 Response
102 >(pool, opts)
103 ]
104 ])
105 }
106
107 /**
108 * Gets the worker choice strategy task statistics requirements in the context.
109 *
110 * @returns The task statistics requirements.
111 */
112 public getTaskStatisticsRequirements (): TaskStatisticsRequirements {
113 return (
114 this.workerChoiceStrategies.get(
115 this.workerChoiceStrategy
116 ) as IWorkerChoiceStrategy
117 ).taskStatisticsRequirements
118 }
119
120 /**
121 * Sets the worker choice strategy to use in the context.
122 *
123 * @param workerChoiceStrategy - The worker choice strategy to set.
124 */
125 public setWorkerChoiceStrategy (
126 workerChoiceStrategy: WorkerChoiceStrategy
127 ): void {
128 if (this.workerChoiceStrategy !== workerChoiceStrategy) {
129 this.workerChoiceStrategy = workerChoiceStrategy
130 }
131 this.workerChoiceStrategies.get(this.workerChoiceStrategy)?.reset()
132 }
133
134 /**
135 * Updates the worker node key in the worker choice strategy internals in the context.
136 *
137 * @returns `true` if the update is successful, `false` otherwise.
138 */
139 public update (workerNodeKey: number): boolean {
140 return (
141 this.workerChoiceStrategies.get(
142 this.workerChoiceStrategy
143 ) as IWorkerChoiceStrategy
144 ).update(workerNodeKey)
145 }
146
147 /**
148 * Executes the worker choice strategy algorithm in the context.
149 *
150 * @returns The key of the worker node.
151 * @throws {@link https://nodejs.org/api/errors.html#class-error} If the worker node key is null or undefined.
152 */
153 public execute (): number {
154 const workerNodeKey = (
155 this.workerChoiceStrategies.get(
156 this.workerChoiceStrategy
157 ) as IWorkerChoiceStrategy
158 ).choose()
159 if (workerNodeKey == null) {
160 throw new Error('Worker node key chosen is null or undefined')
161 }
162 return workerNodeKey
163 }
164
165 /**
166 * Removes the worker node key from the worker choice strategy in the context.
167 *
168 * @param workerNodeKey - The key of the worker node.
169 * @returns `true` if the removal is successful, `false` otherwise.
170 */
171 public remove (workerNodeKey: number): boolean {
172 return (
173 this.workerChoiceStrategies.get(
174 this.workerChoiceStrategy
175 ) as IWorkerChoiceStrategy
176 ).remove(workerNodeKey)
177 }
178
179 /**
180 * Sets the worker choice strategies in the context options.
181 *
182 * @param opts - The worker choice strategy options.
183 */
184 public setOptions (opts: WorkerChoiceStrategyOptions): void {
185 for (const workerChoiceStrategy of this.workerChoiceStrategies.values()) {
186 workerChoiceStrategy.setOptions(opts)
187 }
188 }
189 }