1 import type { IWorker
} from
'./abstract-pool'
2 import type { IPoolInternal
} from
'./pool-internal'
3 import { PoolType
} from
'./pool-internal'
6 * Enumeration of worker choice strategies.
8 export const WorkerChoiceStrategies
= Object.freeze({
10 * Round robin worker selection strategy.
12 ROUND_ROBIN
: 'ROUND_ROBIN',
14 * Less recently used worker selection strategy.
16 LESS_RECENTLY_USED
: 'LESS_RECENTLY_USED'
20 * Worker choice strategy.
22 export type WorkerChoiceStrategy
= keyof
typeof WorkerChoiceStrategies
25 * Worker choice strategy interface.
27 * @template Worker Type of worker which manages the strategy.
29 interface IWorkerChoiceStrategy
<Worker
extends IWorker
> {
31 * Choose a worker in the pool.
37 * Selects the next worker in a round robin fashion.
39 * @template Worker Type of worker which manages the strategy.
40 * @template Data Type of data sent to the worker. This can only be serializable data.
41 * @template Response Type of response of execution. This can only be serializable data.
43 class RoundRobinWorkerChoiceStrategy
<Worker
extends IWorker
, Data
, Response
>
44 implements IWorkerChoiceStrategy
<Worker
>
47 * Index for the next worker.
49 private nextWorkerIndex
: number = 0
52 * Constructs a worker choice strategy that selects in a round robin fashion.
54 * @param pool The pool instance.
57 private readonly pool
: IPoolInternal
<Worker
, Data
, Response
>
61 public choose (): Worker
{
62 const chosenWorker
= this.pool
.workers
[this.nextWorkerIndex
]
63 this.nextWorkerIndex
=
64 this.pool
.workers
.length
- 1 === this.nextWorkerIndex
66 : this.nextWorkerIndex
+ 1
72 * Selects the less recently used worker.
74 * @template Worker Type of worker which manages the strategy.
75 * @template Data Type of data sent to the worker. This can only be serializable data.
76 * @template Response Type of response of execution. This can only be serializable data.
78 class LessRecentlyUsedWorkerChoiceStrategy
<
79 Worker
extends IWorker
,
82 > implements IWorkerChoiceStrategy
<Worker
>
85 * Constructs a worker choice strategy that selects based on less recently used.
87 * @param pool The pool instance.
90 private readonly pool
: IPoolInternal
<Worker
, Data
, Response
>
94 public choose (): Worker
{
95 const isPoolDynamic
= this.pool
.type === PoolType
.DYNAMIC
96 let minNumberOfTasks
= Infinity
97 // A worker is always found because it picks the one with fewer tasks
98 let lessRecentlyUsedWorker
!: Worker
99 for (const [worker
, numberOfTasks
] of this.pool
.tasks
) {
100 if (!isPoolDynamic
&& numberOfTasks
=== 0) {
102 } else if (numberOfTasks
< minNumberOfTasks
) {
103 lessRecentlyUsedWorker
= worker
104 minNumberOfTasks
= numberOfTasks
107 return lessRecentlyUsedWorker
112 * Dynamically choose a worker.
114 * @template Worker Type of worker which manages the strategy.
115 * @template Data Type of data sent to the worker. This can only be serializable data.
116 * @template Response Type of response of execution. This can only be serializable data.
118 class DynamicPoolWorkerChoiceStrategy
<Worker
extends IWorker
, Data
, Response
>
119 implements IWorkerChoiceStrategy
<Worker
>
121 private workerChoiceStrategy
: IWorkerChoiceStrategy
<Worker
>
124 * Constructs a worker choice strategy for dynamical pools.
126 * @param pool The pool instance.
127 * @param createDynamicallyWorkerCallback The worker creation callback for dynamic pool.
128 * @param workerChoiceStrategy The worker choice strategy when the pull is busy.
131 private readonly pool
: IPoolInternal
<Worker
, Data
, Response
>,
132 private createDynamicallyWorkerCallback
: () => Worker
,
133 workerChoiceStrategy
: WorkerChoiceStrategy
= WorkerChoiceStrategies
.ROUND_ROBIN
135 this.workerChoiceStrategy
=
136 SelectionStrategiesUtils
.getWorkerChoiceStrategy(
143 public choose (): Worker
{
144 const freeTaskMapEntry
= this.pool
.findFreeTasksMapEntry()
145 if (freeTaskMapEntry
) {
146 return freeTaskMapEntry
[0]
149 if (this.pool
.busy
) {
150 return this.workerChoiceStrategy
.choose()
153 // All workers are busy, create a new worker
154 return this.createDynamicallyWorkerCallback()
159 * The worker choice strategy context.
161 * @template Worker Type of worker.
162 * @template Data Type of data sent to the worker. This can only be serializable data.
163 * @template Response Type of response of execution. This can only be serializable data.
165 export class WorkerChoiceStrategyContext
<
166 Worker
extends IWorker
,
170 // Will be set by setter in constructor
171 private workerChoiceStrategy
!: IWorkerChoiceStrategy
<Worker
>
174 * Worker choice strategy context constructor.
176 * @param pool The pool instance.
177 * @param createDynamicallyWorkerCallback The worker creation callback for dynamic pool.
178 * @param workerChoiceStrategy The worker choice strategy.
181 private readonly pool
: IPoolInternal
<Worker
, Data
, Response
>,
182 private createDynamicallyWorkerCallback
: () => Worker
,
183 workerChoiceStrategy
: WorkerChoiceStrategy
= WorkerChoiceStrategies
.ROUND_ROBIN
185 this.setWorkerChoiceStrategy(workerChoiceStrategy
)
189 * Get the worker choice strategy instance specific to the pool type.
191 * @param workerChoiceStrategy The worker choice strategy.
192 * @returns The worker choice strategy instance for the pool type.
194 private getPoolWorkerChoiceStrategy (
195 workerChoiceStrategy
: WorkerChoiceStrategy
= WorkerChoiceStrategies
.ROUND_ROBIN
196 ): IWorkerChoiceStrategy
<Worker
> {
197 if (this.pool
.type === PoolType
.DYNAMIC
) {
198 return new DynamicPoolWorkerChoiceStrategy(
200 this.createDynamicallyWorkerCallback
,
204 return SelectionStrategiesUtils
.getWorkerChoiceStrategy(
211 * Set the worker choice strategy to use in the context.
213 * @param workerChoiceStrategy The worker choice strategy to set.
215 public setWorkerChoiceStrategy (
216 workerChoiceStrategy
: WorkerChoiceStrategy
218 this.workerChoiceStrategy
=
219 this.getPoolWorkerChoiceStrategy(workerChoiceStrategy
)
223 * Choose a worker with the underlying selection strategy.
225 * @returns The chosen one.
227 public execute (): Worker
{
228 return this.workerChoiceStrategy
.choose()
233 * Worker selection strategies helpers class.
235 class SelectionStrategiesUtils
{
237 * Get the worker choice strategy instance.
239 * @param pool The pool instance.
240 * @param workerChoiceStrategy The worker choice strategy.
241 * @returns The worker choice strategy instance.
243 public static getWorkerChoiceStrategy
<
244 Worker
extends IWorker
,
248 pool
: IPoolInternal
<Worker
, Data
, Response
>,
249 workerChoiceStrategy
: WorkerChoiceStrategy
= WorkerChoiceStrategies
.ROUND_ROBIN
250 ): IWorkerChoiceStrategy
<Worker
> {
251 switch (workerChoiceStrategy
) {
252 case WorkerChoiceStrategies
.ROUND_ROBIN
:
253 return new RoundRobinWorkerChoiceStrategy(pool
)
254 case WorkerChoiceStrategies
.LESS_RECENTLY_USED
:
255 return new LessRecentlyUsedWorkerChoiceStrategy(pool
)
258 `Worker choice strategy '${workerChoiceStrategy}' not found`