From 058a94577c79d9b62bf54516ea27e0e70f934fcc Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Tue, 6 Jun 2023 21:27:22 +0200 Subject: [PATCH] feat: add least ELU worker choice strategy MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- src/pools/abstract-pool.ts | 2 +- .../least-elu-worker-choice-strategy.ts | 80 +++++++++++++++++++ .../selection-strategies-types.ts | 6 ++ .../worker-choice-strategy-context.ts | 8 ++ 4 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 src/pools/selection-strategies/least-elu-worker-choice-strategy.ts diff --git a/src/pools/abstract-pool.ts b/src/pools/abstract-pool.ts index b86a3b13..b93915c4 100644 --- a/src/pools/abstract-pool.ts +++ b/src/pools/abstract-pool.ts @@ -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 index 00000000..be3c4f5e --- /dev/null +++ b/src/pools/selection-strategies/least-elu-worker-choice-strategy.ts @@ -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 + 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, + 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 + } +} diff --git a/src/pools/selection-strategies/selection-strategies-types.ts b/src/pools/selection-strategies/selection-strategies-types.ts index 4742d069..b96bb029 100644 --- a/src/pools/selection-strategies/selection-strategies-types.ts +++ b/src/pools/selection-strategies/selection-strategies-types.ts @@ -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. */ diff --git a/src/pools/selection-strategies/worker-choice-strategy-context.ts b/src/pools/selection-strategies/worker-choice-strategy-context.ts index 3d32dad6..7862fb38 100644 --- a/src/pools/selection-strategies/worker-choice-strategy-context.ts +++ b/src/pools/selection-strategies/worker-choice-strategy-context.ts @@ -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))( + pool, + opts + ) + ], [ WorkerChoiceStrategies.FAIR_SHARE, new (FairShareWorkerChoiceStrategy.bind(this))( -- 2.34.1