refactor: explicity extends Task for MessageValue type
[poolifier.git] / src / pools / selection-strategies / fair-share-worker-choice-strategy.ts
CommitLineData
f06e48d8 1import type { IWorker } from '../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.
02706357 22 * @typeParam Response - Type of execution response. This can only be serializable data.
23ff945a
JB
23 */
24export class FairShareWorkerChoiceStrategy<
f06e48d8 25 Worker extends IWorker,
b2b1d84e
JB
26 Data = unknown,
27 Response = unknown
bf90656c
JB
28 >
29 extends AbstractWorkerChoiceStrategy<Worker, Data, Response>
17393ac8 30 implements IWorkerChoiceStrategy {
afc003b2 31 /** @inheritDoc */
ea7a90d3 32 public readonly requiredStatistics: RequiredStatistics = {
c6bd2650 33 runTime: true,
78099a15
JB
34 avgRunTime: true,
35 medRunTime: false
10fcfaf4
JB
36 }
37
23ff945a 38 /**
f06e48d8 39 * Worker last virtual task execution timestamp.
23ff945a 40 */
ea7a90d3 41 private readonly workerLastVirtualTaskTimestamp: Map<
c923ce56 42 number,
78cea37e 43 WorkerVirtualTaskTimestamp
c923ce56 44 > = new Map<number, WorkerVirtualTaskTimestamp>()
23ff945a 45
afc003b2 46 /** @inheritDoc */
a6f7f1b4 47 public reset (): boolean {
ea7a90d3
JB
48 this.workerLastVirtualTaskTimestamp.clear()
49 return true
50 }
51
afc003b2 52 /** @inheritDoc */
c923ce56 53 public choose (): number {
23ff945a 54 let minWorkerVirtualTaskEndTimestamp = Infinity
f06e48d8
JB
55 let chosenWorkerNodeKey!: number
56 for (const [index] of this.pool.workerNodes.entries()) {
c923ce56 57 this.computeWorkerLastVirtualTaskTimestamp(index)
23ff945a 58 const workerLastVirtualTaskEndTimestamp =
c923ce56 59 this.workerLastVirtualTaskTimestamp.get(index)?.end ?? 0
23ff945a
JB
60 if (
61 workerLastVirtualTaskEndTimestamp < minWorkerVirtualTaskEndTimestamp
62 ) {
63 minWorkerVirtualTaskEndTimestamp = workerLastVirtualTaskEndTimestamp
f06e48d8 64 chosenWorkerNodeKey = index
23ff945a
JB
65 }
66 }
f06e48d8 67 return chosenWorkerNodeKey
23ff945a
JB
68 }
69
afc003b2 70 /** @inheritDoc */
f06e48d8
JB
71 public remove (workerNodeKey: number): boolean {
72 const deleted = this.workerLastVirtualTaskTimestamp.delete(workerNodeKey)
97a2abc3 73 for (const [key, value] of this.workerLastVirtualTaskTimestamp.entries()) {
f06e48d8 74 if (key > workerNodeKey) {
97a2abc3
JB
75 this.workerLastVirtualTaskTimestamp.set(key - 1, value)
76 }
77 }
f06e48d8 78 return deleted
97a2abc3
JB
79 }
80
23ff945a 81 /**
11df3590
JB
82 * Computes worker last virtual task timestamp.
83 *
f06e48d8 84 * @param workerNodeKey - The worker node key.
23ff945a 85 */
f06e48d8 86 private computeWorkerLastVirtualTaskTimestamp (workerNodeKey: number): void {
11df3590 87 const workerVirtualTaskStartTimestamp = Math.max(
3fafb1b2 88 performance.now(),
f06e48d8 89 this.workerLastVirtualTaskTimestamp.get(workerNodeKey)?.end ?? -Infinity
11df3590 90 )
da309861
JB
91 const workerVirtualTaskTRunTime = this.requiredStatistics.medRunTime
92 ? this.pool.workerNodes[workerNodeKey].tasksUsage.medRunTime
93 : this.pool.workerNodes[workerNodeKey].tasksUsage.avgRunTime
f06e48d8 94 this.workerLastVirtualTaskTimestamp.set(workerNodeKey, {
11df3590 95 start: workerVirtualTaskStartTimestamp,
da309861 96 end: workerVirtualTaskStartTimestamp + (workerVirtualTaskTRunTime ?? 0)
11df3590 97 })
23ff945a
JB
98 }
99}