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
> {
46 * Index for the next worker.
48 private nextWorkerIndex
: number = 0
51 * Constructs a worker choice strategy that selects in a round robin fashion.
53 * @param pool The pool instance.
56 private readonly pool
: IPoolInternal
<Worker
, Data
, Response
>
60 public choose (): Worker
{
61 const chosenWorker
= this.pool
.workers
[this.nextWorkerIndex
]
62 this.nextWorkerIndex
=
63 this.pool
.workers
.length
- 1 === this.nextWorkerIndex
65 : this.nextWorkerIndex
+ 1
71 * Selects the less recently used worker.
73 * @template Worker Type of worker which manages the strategy.
74 * @template Data Type of data sent to the worker. This can only be serializable data.
75 * @template Response Type of response of execution. This can only be serializable data.
77 class LessRecentlyUsedWorkerChoiceStrategy
<
78 Worker
extends IWorker
,
81 > implements IWorkerChoiceStrategy
<Worker
> {
83 * Constructs a worker choice strategy that selects based on less recently used.
85 * @param pool The pool instance.
88 private readonly pool
: IPoolInternal
<Worker
, Data
, Response
>
92 public choose (): Worker
{
93 const isPoolDynamic
= this.pool
.type === PoolType
.DYNAMIC
94 let minNumberOfTasks
= Infinity
95 // A worker is always found because it picks the one with fewer tasks
96 let lessRecentlyUsedWorker
!: Worker
97 for (const [worker
, numberOfTasks
] of this.pool
.tasks
) {
98 if (!isPoolDynamic
&& numberOfTasks
=== 0) {
100 } else if (numberOfTasks
< minNumberOfTasks
) {
101 lessRecentlyUsedWorker
= worker
102 minNumberOfTasks
= numberOfTasks
105 return lessRecentlyUsedWorker
110 * Dynamically choose a worker.
112 * @template Worker Type of worker which manages the strategy.
113 * @template Data Type of data sent to the worker. This can only be serializable data.
114 * @template Response Type of response of execution. This can only be serializable data.
116 class DynamicPoolWorkerChoiceStrategy
<Worker
extends IWorker
, Data
, Response
>
117 implements IWorkerChoiceStrategy
<Worker
> {
118 private workerChoiceStrategy
: IWorkerChoiceStrategy
<Worker
>
121 * Constructs a worker choice strategy for dynamical pools.
123 * @param pool The pool instance.
124 * @param createDynamicallyWorkerCallback The worker creation callback for dynamic pool.
125 * @param workerChoiceStrategy The worker choice strategy when the pull is busy.
128 private readonly pool
: IPoolInternal
<Worker
, Data
, Response
>,
129 private createDynamicallyWorkerCallback
: () => Worker
,
130 workerChoiceStrategy
: WorkerChoiceStrategy
= WorkerChoiceStrategies
.ROUND_ROBIN
132 this.workerChoiceStrategy
= SelectionStrategiesUtils
.getWorkerChoiceStrategy(
139 public choose (): Worker
{
140 const freeTaskMapEntry
= this.pool
.findFreeTasksMapEntry()
141 if (freeTaskMapEntry
) {
142 return freeTaskMapEntry
[0]
145 if (this.pool
.busy
) {
146 return this.workerChoiceStrategy
.choose()
149 // All workers are busy, create a new worker
150 return this.createDynamicallyWorkerCallback()
155 * The worker choice strategy context.
157 * @template Worker Type of worker.
158 * @template Data Type of data sent to the worker. This can only be serializable data.
159 * @template Response Type of response of execution. This can only be serializable data.
161 export class WorkerChoiceStrategyContext
<
162 Worker
extends IWorker
,
166 // Will be set by setter in constructor
167 private workerChoiceStrategy
!: IWorkerChoiceStrategy
<Worker
>
170 * Worker choice strategy context constructor.
172 * @param pool The pool instance.
173 * @param createDynamicallyWorkerCallback The worker creation callback for dynamic pool.
174 * @param workerChoiceStrategy The worker choice strategy.
177 private readonly pool
: IPoolInternal
<Worker
, Data
, Response
>,
178 private createDynamicallyWorkerCallback
: () => Worker
,
179 workerChoiceStrategy
: WorkerChoiceStrategy
= WorkerChoiceStrategies
.ROUND_ROBIN
181 this.setWorkerChoiceStrategy(workerChoiceStrategy
)
185 * Get the worker choice strategy instance specific to the pool type.
187 * @param workerChoiceStrategy The worker choice strategy.
188 * @returns The worker choice strategy instance for the pool type.
190 private getPoolWorkerChoiceStrategy (
191 workerChoiceStrategy
: WorkerChoiceStrategy
= WorkerChoiceStrategies
.ROUND_ROBIN
192 ): IWorkerChoiceStrategy
<Worker
> {
193 if (this.pool
.type === PoolType
.DYNAMIC
) {
194 return new DynamicPoolWorkerChoiceStrategy(
196 this.createDynamicallyWorkerCallback
,
200 return SelectionStrategiesUtils
.getWorkerChoiceStrategy(
207 * Set the worker choice strategy to use in the context.
209 * @param workerChoiceStrategy The worker choice strategy to set.
211 public setWorkerChoiceStrategy (
212 workerChoiceStrategy
: WorkerChoiceStrategy
214 this.workerChoiceStrategy
= this.getPoolWorkerChoiceStrategy(
220 * Choose a worker with the underlying selection strategy.
222 * @returns The chosen one.
224 public execute (): Worker
{
225 return this.workerChoiceStrategy
.choose()
230 * Worker selection strategies helpers class.
232 class SelectionStrategiesUtils
{
234 * Get the worker choice strategy instance.
236 * @param pool The pool instance.
237 * @param workerChoiceStrategy The worker choice strategy.
238 * @returns The worker choice strategy instance.
240 public static getWorkerChoiceStrategy
<
241 Worker
extends IWorker
,
245 pool
: IPoolInternal
<Worker
, Data
, Response
>,
246 workerChoiceStrategy
: WorkerChoiceStrategy
= WorkerChoiceStrategies
.ROUND_ROBIN
247 ): IWorkerChoiceStrategy
<Worker
> {
248 switch (workerChoiceStrategy
) {
249 case WorkerChoiceStrategies
.ROUND_ROBIN
:
250 return new RoundRobinWorkerChoiceStrategy(pool
)
251 case WorkerChoiceStrategies
.LESS_RECENTLY_USED
:
252 return new LessRecentlyUsedWorkerChoiceStrategy(pool
)
255 `Worker choice strategy '${workerChoiceStrategy}' not found`