feat: add least ELU worker choice strategy
authorJérôme Benoit <jerome.benoit@sap.com>
Tue, 6 Jun 2023 19:27:22 +0000 (21:27 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Tue, 6 Jun 2023 19:27:22 +0000 (21:27 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/pools/abstract-pool.ts
src/pools/selection-strategies/least-elu-worker-choice-strategy.ts [new file with mode: 0644]
src/pools/selection-strategies/selection-strategies-types.ts
src/pools/selection-strategies/worker-choice-strategy-context.ts

index b86a3b13a6b538efb4024c0ebe8e49df22e4a1a8..b93915c48e31111b93eb2199ce50fd26dae222b6 100644 (file)
@@ -536,7 +536,7 @@ export abstract class AbstractPool<
           idle: workerTasksUsage.elu.idle + message.elu.idle,
           active: workerTasksUsage.elu.active + message.elu.active,
           utilization:
-            workerTasksUsage.elu.utilization + message.elu.utilization
+            (workerTasksUsage.elu.utilization + message.elu.utilization) / 2
         }
       } else if (message.elu != null) {
         workerTasksUsage.elu = message.elu
diff --git a/src/pools/selection-strategies/least-elu-worker-choice-strategy.ts b/src/pools/selection-strategies/least-elu-worker-choice-strategy.ts
new file mode 100644 (file)
index 0000000..be3c4f5
--- /dev/null
@@ -0,0 +1,80 @@
+import { DEFAULT_WORKER_CHOICE_STRATEGY_OPTIONS } from '../../utils'
+import type { IPool } from '../pool'
+import type { IWorker } from '../worker'
+import { AbstractWorkerChoiceStrategy } from './abstract-worker-choice-strategy'
+import type {
+  IWorkerChoiceStrategy,
+  TaskStatistics,
+  WorkerChoiceStrategyOptions
+} from './selection-strategies-types'
+
+/**
+ * Selects the worker with the least ELU.
+ *
+ * @typeParam Worker - Type of worker which manages the strategy.
+ * @typeParam Data - Type of data sent to the worker. This can only be serializable data.
+ * @typeParam Response - Type of execution response. This can only be serializable data.
+ */
+export class LeastEluWorkerChoiceStrategy<
+    Worker extends IWorker,
+    Data = unknown,
+    Response = unknown
+  >
+  extends AbstractWorkerChoiceStrategy<Worker, Data, Response>
+  implements IWorkerChoiceStrategy {
+  /** @inheritDoc */
+  public readonly taskStatistics: TaskStatistics = {
+    runTime: false,
+    avgRunTime: true,
+    medRunTime: false,
+    waitTime: false,
+    avgWaitTime: false,
+    medWaitTime: false,
+    elu: true
+  }
+
+  /** @inheritDoc */
+  public constructor (
+    pool: IPool<Worker, Data, Response>,
+    opts: WorkerChoiceStrategyOptions = DEFAULT_WORKER_CHOICE_STRATEGY_OPTIONS
+  ) {
+    super(pool, opts)
+    this.setTaskStatistics(this.opts)
+  }
+
+  /** @inheritDoc */
+  public reset (): boolean {
+    return true
+  }
+
+  /** @inheritDoc */
+  public update (): boolean {
+    return true
+  }
+
+  /** @inheritDoc */
+  public choose (): number {
+    // const freeWorkerNodeKey = this.findFreeWorkerNodeKey()
+    // if (freeWorkerNodeKey !== -1) {
+    //   return freeWorkerNodeKey
+    // }
+    let minTasksElu = Infinity
+    let leastEluWorkerNodeKey!: number
+    for (const [workerNodeKey, workerNode] of this.pool.workerNodes.entries()) {
+      const tasksUsage = workerNode.tasksUsage
+      const tasksElu = tasksUsage.elu?.utilization ?? 0
+      if (tasksElu === 0) {
+        return workerNodeKey
+      } else if (tasksElu < minTasksElu) {
+        minTasksElu = tasksElu
+        leastEluWorkerNodeKey = workerNodeKey
+      }
+    }
+    return leastEluWorkerNodeKey
+  }
+
+  /** @inheritDoc */
+  public remove (): boolean {
+    return true
+  }
+}
index 4742d069594fed9324d6c880ef44b921593a7622..b96bb029a0befe39ce438beb368e2c0dbecb87ab 100644 (file)
@@ -14,6 +14,12 @@ export const WorkerChoiceStrategies = Object.freeze({
    * Least busy worker selection strategy.
    */
   LEAST_BUSY: 'LEAST_BUSY',
+  /**
+   * Least ELU worker selection strategy.
+   *
+   * @experimental
+   */
+  LEAST_ELU: 'LEAST_ELU',
   /**
    * Fair share worker selection strategy.
    */
index 3d32dad68eee8b700a6aed3b2a4811876d978427..7862fb38536b702e850843dc77d6303b637eada4 100644 (file)
@@ -5,6 +5,7 @@ import { FairShareWorkerChoiceStrategy } from './fair-share-worker-choice-strate
 import { InterleavedWeightedRoundRobinWorkerChoiceStrategy } from './interleaved-weighted-round-robin-worker-choice-strategy'
 import { LeastBusyWorkerChoiceStrategy } from './least-busy-worker-choice-strategy'
 import { LeastUsedWorkerChoiceStrategy } from './least-used-worker-choice-strategy'
+import { LeastEluWorkerChoiceStrategy } from './least-elu-worker-choice-strategy'
 import { RoundRobinWorkerChoiceStrategy } from './round-robin-worker-choice-strategy'
 import type {
   IWorkerChoiceStrategy,
@@ -70,6 +71,13 @@ export class WorkerChoiceStrategyContext<
           opts
         )
       ],
+      [
+        WorkerChoiceStrategies.LEAST_ELU,
+        new (LeastEluWorkerChoiceStrategy.bind(this))<Worker, Data, Response>(
+          pool,
+          opts
+        )
+      ],
       [
         WorkerChoiceStrategies.FAIR_SHARE,
         new (FairShareWorkerChoiceStrategy.bind(this))<Worker, Data, Response>(