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