perf: pickup free worker in the less busy and used strategies for fixed
[poolifier.git] / src / pools / selection-strategies / fair-share-worker-choice-strategy.ts
CommitLineData
ea7a90d3 1import type { IPoolWorker } from '../pool-worker'
23ff945a 2import { AbstractWorkerChoiceStrategy } from './abstract-worker-choice-strategy'
10fcfaf4 3import type { RequiredStatistics } from './selection-strategies-types'
23ff945a
JB
4
5/**
6 * Worker virtual task timestamp.
7 */
78cea37e 8interface WorkerVirtualTaskTimestamp {
23ff945a
JB
9 start: number
10 end: number
11}
12
13/**
14 * Selects the next worker with a fair share scheduling algorithm.
15 * Loosely modeled after the fair queueing algorithm: https://en.wikipedia.org/wiki/Fair_queuing.
16 *
38e795c1
JB
17 * @typeParam Worker - Type of worker which manages the strategy.
18 * @typeParam Data - Type of data sent to the worker. This can only be serializable data.
19 * @typeParam Response - Type of response of execution. This can only be serializable data.
23ff945a
JB
20 */
21export class FairShareWorkerChoiceStrategy<
ea7a90d3 22 Worker extends IPoolWorker,
23ff945a
JB
23 Data,
24 Response
25> extends AbstractWorkerChoiceStrategy<Worker, Data, Response> {
38e795c1 26 /** {@inheritDoc} */
ea7a90d3 27 public readonly requiredStatistics: RequiredStatistics = {
10fcfaf4
JB
28 runTime: true
29 }
30
23ff945a
JB
31 /**
32 * Worker last virtual task execution timestamp.
33 */
ea7a90d3 34 private readonly workerLastVirtualTaskTimestamp: Map<
c923ce56 35 number,
78cea37e 36 WorkerVirtualTaskTimestamp
c923ce56 37 > = new Map<number, WorkerVirtualTaskTimestamp>()
23ff945a 38
38e795c1 39 /** {@inheritDoc} */
a6f7f1b4 40 public reset (): boolean {
ea7a90d3
JB
41 this.workerLastVirtualTaskTimestamp.clear()
42 return true
43 }
44
38e795c1 45 /** {@inheritDoc} */
c923ce56 46 public choose (): number {
23ff945a 47 let minWorkerVirtualTaskEndTimestamp = Infinity
c923ce56
JB
48 let chosenWorkerKey!: number
49 for (const [index] of this.pool.workers.entries()) {
50 this.computeWorkerLastVirtualTaskTimestamp(index)
23ff945a 51 const workerLastVirtualTaskEndTimestamp =
c923ce56 52 this.workerLastVirtualTaskTimestamp.get(index)?.end ?? 0
23ff945a
JB
53 if (
54 workerLastVirtualTaskEndTimestamp < minWorkerVirtualTaskEndTimestamp
55 ) {
56 minWorkerVirtualTaskEndTimestamp = workerLastVirtualTaskEndTimestamp
c923ce56 57 chosenWorkerKey = index
23ff945a
JB
58 }
59 }
c923ce56 60 return chosenWorkerKey
23ff945a
JB
61 }
62
97a2abc3
JB
63 /** {@inheritDoc} */
64 public remove (workerKey: number): boolean {
65 const workerDeleted = this.workerLastVirtualTaskTimestamp.delete(workerKey)
66 for (const [key, value] of this.workerLastVirtualTaskTimestamp.entries()) {
67 if (key > workerKey) {
68 this.workerLastVirtualTaskTimestamp.set(key - 1, value)
69 }
70 }
71 return workerDeleted
72 }
73
23ff945a 74 /**
11df3590
JB
75 * Computes worker last virtual task timestamp.
76 *
c923ce56 77 * @param workerKey - The worker key.
23ff945a 78 */
c923ce56 79 private computeWorkerLastVirtualTaskTimestamp (workerKey: number): void {
11df3590
JB
80 const workerVirtualTaskStartTimestamp = Math.max(
81 Date.now(),
c923ce56 82 this.workerLastVirtualTaskTimestamp.get(workerKey)?.end ?? -Infinity
11df3590 83 )
c923ce56 84 this.workerLastVirtualTaskTimestamp.set(workerKey, {
11df3590 85 start: workerVirtualTaskStartTimestamp,
61d849ff
JB
86 end:
87 workerVirtualTaskStartTimestamp +
c923ce56 88 (this.pool.workers[workerKey].tasksUsage.avgRunTime ?? 0)
11df3590 89 })
23ff945a
JB
90 }
91}