From: Jérôme Benoit Date: Thu, 2 May 2024 11:13:11 +0000 (+0200) Subject: fix: fix worker choice strategies behavior X-Git-Tag: v4.0.1~1 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=e0843544927da7ce67c7a6b84c5bf402dd47c1bb;p=poolifier.git fix: fix worker choice strategies behavior Signed-off-by: Jérôme Benoit --- diff --git a/CHANGELOG.md b/CHANGELOG.md index e9d570eb..27bbb987 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Ensure dynamic worker node are initialized with sensible worker node usage default values to avoid worker choice strategies biased decisions. +- Account for tasks wait time in task execution time computation in worker choice strategies to avoid biased decisions under load with several prioritized task functions and tasks queue enabled. + ## [4.0.0] - 2024-04-30 ### Changed diff --git a/docs/api.md b/docs/api.md index dd9f833c..1b888173 100644 --- a/docs/api.md +++ b/docs/api.md @@ -98,7 +98,7 @@ An object with these properties: - `workerChoiceStrategy` (optional) - The default worker choice strategy to use in this pool: - `WorkerChoiceStrategies.ROUND_ROBIN`: Submit tasks to worker in a round robin fashion - - `WorkerChoiceStrategies.LEAST_USED`: Submit tasks to the worker with the minimum number of executed, executing and queued tasks + - `WorkerChoiceStrategies.LEAST_USED`: Submit tasks to the worker with the minimum number of executing and queued tasks - `WorkerChoiceStrategies.LEAST_BUSY`: Submit tasks to the worker with the minimum tasks total execution and wait time - `WorkerChoiceStrategies.LEAST_ELU`: Submit tasks to the worker with the minimum event loop utilization (ELU) - `WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN`: Submit tasks to worker by using a [weighted round robin scheduling algorithm](./worker-choice-strategies.md#weighted-round-robin) based on tasks execution time diff --git a/src/pools/abstract-pool.ts b/src/pools/abstract-pool.ts index 4f60dff0..677d33b6 100644 --- a/src/pools/abstract-pool.ts +++ b/src/pools/abstract-pool.ts @@ -168,7 +168,7 @@ export abstract class AbstractPool< this.enqueueTask = this.enqueueTask.bind(this) if (this.opts.enableEvents === true) { - this.initializeEventEmitter() + this.initEventEmitter() } this.workerChoiceStrategiesContext = new WorkerChoiceStrategiesContext< Worker, @@ -281,7 +281,7 @@ export abstract class AbstractPool< } } - private initializeEventEmitter (): void { + private initEventEmitter (): void { this.emitter = new EventEmitterAsyncResource({ name: `poolifier:${this.type}-${this.worker}-pool` }) @@ -1061,7 +1061,7 @@ export abstract class AbstractPool< /** * Starts the minimum number of workers. */ - private startMinimumNumberOfWorkers (): void { + private startMinimumNumberOfWorkers (initWorkerNodeUsage = false): void { this.startingMinimumNumberOfWorkers = true while ( this.workerNodes.reduce( @@ -1070,7 +1070,9 @@ export abstract class AbstractPool< 0 ) < this.minimumNumberOfWorkers ) { - this.createAndSetupWorkerNode() + const workerNodeKey = this.createAndSetupWorkerNode() + initWorkerNodeUsage && + this.initWorkerNodeUsage(this.workerNodes[workerNodeKey]) } this.startingMinimumNumberOfWorkers = false } @@ -1338,6 +1340,44 @@ export abstract class AbstractPool< transferList?: readonly TransferListItem[] ): void + /** + * Initializes the worker node usage with sensible default values gathered during runtime. + * + * @param workerNode - The worker node. + */ + private initWorkerNodeUsage (workerNode: IWorkerNode): void { + if ( + this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements() + .runTime.aggregate === true + ) { + workerNode.usage.runTime.aggregate = min( + ...this.workerNodes.map( + workerNode => workerNode.usage.runTime.aggregate ?? Infinity + ) + ) + } + if ( + this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements() + .waitTime.aggregate === true + ) { + workerNode.usage.waitTime.aggregate = min( + ...this.workerNodes.map( + workerNode => workerNode.usage.waitTime.aggregate ?? Infinity + ) + ) + } + if ( + this.workerChoiceStrategiesContext?.getTaskStatisticsRequirements().elu + .aggregate === true + ) { + workerNode.usage.elu.active.aggregate = min( + ...this.workerNodes.map( + workerNode => workerNode.usage.elu.active.aggregate ?? Infinity + ) + ) + } + } + /** * Creates a new, completely set up worker node. * @@ -1368,7 +1408,7 @@ export abstract class AbstractPool< if (workerNode.info.dynamic) { this.createAndSetupDynamicWorkerNode() } else if (!this.startingMinimumNumberOfWorkers) { - this.startMinimumNumberOfWorkers() + this.startMinimumNumberOfWorkers(true) } } if ( @@ -1394,7 +1434,7 @@ export abstract class AbstractPool< !this.startingMinimumNumberOfWorkers && !this.destroying ) { - this.startMinimumNumberOfWorkers() + this.startMinimumNumberOfWorkers(true) } }) const workerNodeKey = this.addWorkerNode(workerNode) @@ -1459,6 +1499,7 @@ export abstract class AbstractPool< ) { workerNode.info.ready = true } + this.initWorkerNodeUsage(workerNode) this.checkAndEmitDynamicWorkerCreationEvents() return workerNodeKey } diff --git a/src/pools/selection-strategies/abstract-worker-choice-strategy.ts b/src/pools/selection-strategies/abstract-worker-choice-strategy.ts index 849b8a4f..2b40f0c6 100644 --- a/src/pools/selection-strategies/abstract-worker-choice-strategy.ts +++ b/src/pools/selection-strategies/abstract-worker-choice-strategy.ts @@ -133,7 +133,7 @@ export abstract class AbstractWorkerChoiceStrategy< /** * Gets the worker node task runtime. * If the task statistics require the average runtime, the average runtime is returned. - * If the task statistics require the median runtime , the median runtime is returned. + * If the task statistics require the median runtime, the median runtime is returned. * * @param workerNodeKey - The worker node key. * @returns The worker node task runtime. diff --git a/src/pools/selection-strategies/fair-share-worker-choice-strategy.ts b/src/pools/selection-strategies/fair-share-worker-choice-strategy.ts index ee617d36..2f2686e9 100644 --- a/src/pools/selection-strategies/fair-share-worker-choice-strategy.ts +++ b/src/pools/selection-strategies/fair-share-worker-choice-strategy.ts @@ -1,5 +1,4 @@ import type { IPool } from '../pool.js' -import { DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS } from '../utils.js' import type { IWorker } from '../worker.js' import { AbstractWorkerChoiceStrategy } from './abstract-worker-choice-strategy.js' import { @@ -31,7 +30,11 @@ export class FairShareWorkerChoiceStrategy< average: true, median: false }, - waitTime: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS, + waitTime: { + aggregate: true, + average: true, + median: false + }, elu: { aggregate: true, average: true, @@ -120,12 +123,13 @@ export class FairShareWorkerChoiceStrategy< workerNodeKey: number, workerNodeVirtualTaskStartTimestamp: number ): number { - const workerNodeTaskRunTime = + const workerNodeTaskExecutionTime = + this.getWorkerNodeTaskWaitTime(workerNodeKey) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this.opts!.measurement === Measurements.elu + (this.opts!.measurement === Measurements.elu ? this.getWorkerNodeTaskElu(workerNodeKey) - : this.getWorkerNodeTaskRunTime(workerNodeKey) - return workerNodeVirtualTaskStartTimestamp + workerNodeTaskRunTime + : this.getWorkerNodeTaskRunTime(workerNodeKey)) + return workerNodeVirtualTaskStartTimestamp + workerNodeTaskExecutionTime } private getWorkerNodeVirtualTaskStartTimestamp ( diff --git a/src/pools/selection-strategies/interleaved-weighted-round-robin-worker-choice-strategy.ts b/src/pools/selection-strategies/interleaved-weighted-round-robin-worker-choice-strategy.ts index b1abe987..4048924c 100644 --- a/src/pools/selection-strategies/interleaved-weighted-round-robin-worker-choice-strategy.ts +++ b/src/pools/selection-strategies/interleaved-weighted-round-robin-worker-choice-strategy.ts @@ -29,7 +29,11 @@ export class InterleavedWeightedRoundRobinWorkerChoiceStrategy< average: true, median: false }, - waitTime: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS, + waitTime: { + aggregate: true, + average: true, + median: false + }, elu: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS } @@ -46,9 +50,9 @@ export class InterleavedWeightedRoundRobinWorkerChoiceStrategy< */ private workerNodeId = 0 /** - * Worker node virtual task runtime. + * Worker node virtual execution time. */ - private workerNodeVirtualTaskRunTime = 0 + private workerNodeVirtualTaskExecutionTime = 0 /** @inheritDoc */ public constructor ( @@ -65,7 +69,7 @@ export class InterleavedWeightedRoundRobinWorkerChoiceStrategy< this.resetWorkerNodeKeyProperties() this.roundId = 0 this.workerNodeId = 0 - this.workerNodeVirtualTaskRunTime = 0 + this.workerNodeVirtualTaskExecutionTime = 0 return true } @@ -90,19 +94,19 @@ export class InterleavedWeightedRoundRobinWorkerChoiceStrategy< this.workerNodeId = workerNodeKey if ( this.workerNodeId !== this.nextWorkerNodeKey && - this.workerNodeVirtualTaskRunTime !== 0 + this.workerNodeVirtualTaskExecutionTime !== 0 ) { - this.workerNodeVirtualTaskRunTime = 0 + this.workerNodeVirtualTaskExecutionTime = 0 } // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const workerWeight = this.opts!.weights![workerNodeKey] if ( this.isWorkerNodeReady(workerNodeKey) && workerWeight >= this.roundWeights[roundIndex] && - this.workerNodeVirtualTaskRunTime < workerWeight + this.workerNodeVirtualTaskExecutionTime < workerWeight ) { - this.workerNodeVirtualTaskRunTime = - this.workerNodeVirtualTaskRunTime + + this.workerNodeVirtualTaskExecutionTime += + this.getWorkerNodeTaskWaitTime(workerNodeKey) + this.getWorkerNodeTaskRunTime(workerNodeKey) this.setPreviousWorkerNodeKey(this.nextWorkerNodeKey) this.nextWorkerNodeKey = workerNodeKey @@ -135,7 +139,7 @@ export class InterleavedWeightedRoundRobinWorkerChoiceStrategy< if (this.pool.workerNodes.length === 0) { this.resetWorkerNodeKeyProperties() this.workerNodeId = 0 - this.workerNodeVirtualTaskRunTime = 0 + this.workerNodeVirtualTaskExecutionTime = 0 return true } if ( diff --git a/src/pools/selection-strategies/least-busy-worker-choice-strategy.ts b/src/pools/selection-strategies/least-busy-worker-choice-strategy.ts index 8db32ac7..a9fe3d1c 100644 --- a/src/pools/selection-strategies/least-busy-worker-choice-strategy.ts +++ b/src/pools/selection-strategies/least-busy-worker-choice-strategy.ts @@ -75,10 +75,10 @@ export class LeastBusyWorkerChoiceStrategy< return this.pool.workerNodes.reduce( (minWorkerNodeKey, workerNode, workerNodeKey, workerNodes) => { return this.isWorkerNodeReady(workerNodeKey) && - (workerNode.usage.runTime.aggregate ?? 0) + - (workerNode.usage.waitTime.aggregate ?? 0) < - (workerNodes[minWorkerNodeKey].usage.runTime.aggregate ?? 0) + - (workerNodes[minWorkerNodeKey].usage.waitTime.aggregate ?? 0) + (workerNode.usage.waitTime.aggregate ?? 0) + + (workerNode.usage.runTime.aggregate ?? 0) < + (workerNodes[minWorkerNodeKey].usage.waitTime.aggregate ?? 0) + + (workerNodes[minWorkerNodeKey].usage.runTime.aggregate ?? 0) ? workerNodeKey : minWorkerNodeKey }, diff --git a/src/pools/selection-strategies/least-used-worker-choice-strategy.ts b/src/pools/selection-strategies/least-used-worker-choice-strategy.ts index e45d5754..cd93d752 100644 --- a/src/pools/selection-strategies/least-used-worker-choice-strategy.ts +++ b/src/pools/selection-strategies/least-used-worker-choice-strategy.ts @@ -57,11 +57,8 @@ export class LeastUsedWorkerChoiceStrategy< return this.pool.workerNodes.reduce( (minWorkerNodeKey, workerNode, workerNodeKey, workerNodes) => { return this.isWorkerNodeReady(workerNodeKey) && - workerNode.usage.tasks.executed + - workerNode.usage.tasks.executing + - workerNode.usage.tasks.queued < - workerNodes[minWorkerNodeKey].usage.tasks.executed + - workerNodes[minWorkerNodeKey].usage.tasks.executing + + workerNode.usage.tasks.executing + workerNode.usage.tasks.queued < + workerNodes[minWorkerNodeKey].usage.tasks.executing + workerNodes[minWorkerNodeKey].usage.tasks.queued ? workerNodeKey : minWorkerNodeKey diff --git a/src/pools/selection-strategies/weighted-round-robin-worker-choice-strategy.ts b/src/pools/selection-strategies/weighted-round-robin-worker-choice-strategy.ts index f0484778..6ce55c9a 100644 --- a/src/pools/selection-strategies/weighted-round-robin-worker-choice-strategy.ts +++ b/src/pools/selection-strategies/weighted-round-robin-worker-choice-strategy.ts @@ -30,14 +30,18 @@ export class WeightedRoundRobinWorkerChoiceStrategy< average: true, median: false }, - waitTime: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS, + waitTime: { + aggregate: true, + average: true, + median: false + }, elu: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS } /** - * Worker node virtual task runtime. + * Worker node virtual execution time. */ - private workerNodeVirtualTaskRunTime = 0 + private workerNodeVirtualTaskExecutionTime = 0 /** @inheritDoc */ public constructor ( @@ -51,7 +55,7 @@ export class WeightedRoundRobinWorkerChoiceStrategy< /** @inheritDoc */ public reset (): boolean { this.resetWorkerNodeKeyProperties() - this.workerNodeVirtualTaskRunTime = 0 + this.workerNodeVirtualTaskExecutionTime = 0 return true } @@ -75,7 +79,7 @@ export class WeightedRoundRobinWorkerChoiceStrategy< return true } if (this.nextWorkerNodeKey === workerNodeKey) { - this.workerNodeVirtualTaskRunTime = 0 + this.workerNodeVirtualTaskExecutionTime = 0 if (this.nextWorkerNodeKey > this.pool.workerNodes.length - 1) { this.nextWorkerNodeKey = this.pool.workerNodes.length - 1 } @@ -93,9 +97,11 @@ export class WeightedRoundRobinWorkerChoiceStrategy< const workerWeight = // eslint-disable-next-line @typescript-eslint/no-non-null-assertion this.opts!.weights![this.nextWorkerNodeKey ?? this.previousWorkerNodeKey] - if (this.workerNodeVirtualTaskRunTime < workerWeight) { - this.workerNodeVirtualTaskRunTime = - this.workerNodeVirtualTaskRunTime + + if (this.workerNodeVirtualTaskExecutionTime < workerWeight) { + this.workerNodeVirtualTaskExecutionTime += + this.getWorkerNodeTaskWaitTime( + this.nextWorkerNodeKey ?? this.previousWorkerNodeKey + ) + this.getWorkerNodeTaskRunTime( this.nextWorkerNodeKey ?? this.previousWorkerNodeKey ) @@ -104,7 +110,7 @@ export class WeightedRoundRobinWorkerChoiceStrategy< this.nextWorkerNodeKey === this.pool.workerNodes.length - 1 ? 0 : (this.nextWorkerNodeKey ?? this.previousWorkerNodeKey) + 1 - this.workerNodeVirtualTaskRunTime = 0 + this.workerNodeVirtualTaskExecutionTime = 0 } return this.nextWorkerNodeKey } diff --git a/tests/pools/abstract-pool.test.mjs b/tests/pools/abstract-pool.test.mjs index 313cc77a..42e2959b 100644 --- a/tests/pools/abstract-pool.test.mjs +++ b/tests/pools/abstract-pool.test.mjs @@ -468,8 +468,8 @@ describe('Abstract pool test suite', () => { median: false }, waitTime: { - aggregate: false, - average: false, + aggregate: true, + average: true, median: false }, elu: { @@ -507,8 +507,8 @@ describe('Abstract pool test suite', () => { median: true }, waitTime: { - aggregate: false, - average: false, + aggregate: true, + average: true, median: false }, elu: { @@ -546,8 +546,8 @@ describe('Abstract pool test suite', () => { median: false }, waitTime: { - aggregate: false, - average: false, + aggregate: true, + average: true, median: false }, elu: { diff --git a/tests/pools/selection-strategies/selection-strategies.test.mjs b/tests/pools/selection-strategies/selection-strategies.test.mjs index 345c2af8..e4d1dd07 100644 --- a/tests/pools/selection-strategies/selection-strategies.test.mjs +++ b/tests/pools/selection-strategies/selection-strategies.test.mjs @@ -112,7 +112,7 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategiesContext.workerChoiceStrategies.get( workerChoiceStrategy - ).workerNodeVirtualTaskRunTime + ).workerNodeVirtualTaskExecutionTime ).toBe(0) } else if ( workerChoiceStrategy === @@ -121,7 +121,7 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategiesContext.workerChoiceStrategies.get( workerChoiceStrategy - ).workerNodeVirtualTaskRunTime + ).workerNodeVirtualTaskExecutionTime ).toBe(0) expect( pool.workerChoiceStrategiesContext.workerChoiceStrategies.get( @@ -1116,8 +1116,8 @@ describe('Selection strategies test suite', () => { median: false }, waitTime: { - aggregate: false, - average: false, + aggregate: true, + average: true, median: false }, elu: { @@ -1142,8 +1142,8 @@ describe('Selection strategies test suite', () => { median: false }, waitTime: { - aggregate: false, - average: false, + aggregate: true, + average: true, median: false }, elu: { @@ -1183,9 +1183,9 @@ describe('Selection strategies test suite', () => { runTime: expect.objectContaining({ history: expect.any(CircularArray) }), - waitTime: { - history: new CircularArray() - }, + waitTime: expect.objectContaining({ + history: expect.any(CircularArray) + }), elu: expect.objectContaining({ idle: expect.objectContaining({ history: expect.any(CircularArray) @@ -1209,6 +1209,16 @@ describe('Selection strategies test suite', () => { } else { expect(workerNode.usage.runTime.average).toBeGreaterThan(0) } + if (workerNode.usage.waitTime.aggregate == null) { + expect(workerNode.usage.waitTime.aggregate).toBeUndefined() + } else { + expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0) + } + if (workerNode.usage.waitTime.average == null) { + expect(workerNode.usage.waitTime.average).toBeUndefined() + } else { + expect(workerNode.usage.waitTime.average).toBeGreaterThan(0) + } if (workerNode.usage.elu.active.aggregate == null) { expect(workerNode.usage.elu.active.aggregate).toBeUndefined() } else { @@ -1269,9 +1279,9 @@ describe('Selection strategies test suite', () => { runTime: expect.objectContaining({ history: expect.any(CircularArray) }), - waitTime: { - history: new CircularArray() - }, + waitTime: expect.objectContaining({ + history: expect.any(CircularArray) + }), elu: expect.objectContaining({ idle: expect.objectContaining({ history: expect.any(CircularArray) @@ -1295,6 +1305,16 @@ describe('Selection strategies test suite', () => { } else { expect(workerNode.usage.runTime.average).toBeGreaterThan(0) } + if (workerNode.usage.waitTime.aggregate == null) { + expect(workerNode.usage.waitTime.aggregate).toBeUndefined() + } else { + expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0) + } + if (workerNode.usage.waitTime.average == null) { + expect(workerNode.usage.waitTime.average).toBeUndefined() + } else { + expect(workerNode.usage.waitTime.average).toBeGreaterThan(0) + } if (workerNode.usage.elu.active.aggregate == null) { expect(workerNode.usage.elu.active.aggregate).toBeUndefined() } else { @@ -1360,9 +1380,9 @@ describe('Selection strategies test suite', () => { runTime: expect.objectContaining({ history: expect.any(CircularArray) }), - waitTime: { - history: new CircularArray() - }, + waitTime: expect.objectContaining({ + history: expect.any(CircularArray) + }), elu: expect.objectContaining({ idle: expect.objectContaining({ history: expect.any(CircularArray) @@ -1386,6 +1406,16 @@ describe('Selection strategies test suite', () => { } else { expect(workerNode.usage.runTime.median).toBeGreaterThan(0) } + if (workerNode.usage.waitTime.aggregate == null) { + expect(workerNode.usage.waitTime.aggregate).toBeUndefined() + } else { + expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0) + } + if (workerNode.usage.waitTime.median == null) { + expect(workerNode.usage.waitTime.median).toBeUndefined() + } else { + expect(workerNode.usage.waitTime.median).toBeGreaterThan(0) + } if (workerNode.usage.elu.active.aggregate == null) { expect(workerNode.usage.elu.active.aggregate).toBeUndefined() } else { @@ -1494,8 +1524,8 @@ describe('Selection strategies test suite', () => { median: false }, waitTime: { - aggregate: false, - average: false, + aggregate: true, + average: true, median: false }, elu: { @@ -1520,8 +1550,8 @@ describe('Selection strategies test suite', () => { median: false }, waitTime: { - aggregate: false, - average: false, + aggregate: true, + average: true, median: false }, elu: { @@ -1561,9 +1591,9 @@ describe('Selection strategies test suite', () => { runTime: expect.objectContaining({ history: expect.any(CircularArray) }), - waitTime: { - history: new CircularArray() - }, + waitTime: expect.objectContaining({ + history: expect.any(CircularArray) + }), elu: { idle: { history: new CircularArray() @@ -1587,6 +1617,16 @@ describe('Selection strategies test suite', () => { } else { expect(workerNode.usage.runTime.average).toBeGreaterThan(0) } + if (workerNode.usage.waitTime.aggregate == null) { + expect(workerNode.usage.waitTime.aggregate).toBeUndefined() + } else { + expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0) + } + if (workerNode.usage.waitTime.average == null) { + expect(workerNode.usage.waitTime.average).toBeUndefined() + } else { + expect(workerNode.usage.waitTime.average).toBeGreaterThan(0) + } } expect( pool.workerChoiceStrategiesContext.workerChoiceStrategies.get( @@ -1601,7 +1641,7 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategiesContext.workerChoiceStrategies.get( pool.workerChoiceStrategiesContext.defaultWorkerChoiceStrategy - ).workerNodeVirtualTaskRunTime + ).workerNodeVirtualTaskExecutionTime ).toBeGreaterThanOrEqual(0) // We need to clean up the resources after our test await pool.destroy() @@ -1635,9 +1675,9 @@ describe('Selection strategies test suite', () => { runTime: expect.objectContaining({ history: expect.any(CircularArray) }), - waitTime: { - history: new CircularArray() - }, + waitTime: expect.objectContaining({ + history: expect.any(CircularArray) + }), elu: { idle: { history: new CircularArray() @@ -1661,6 +1701,16 @@ describe('Selection strategies test suite', () => { } else { expect(workerNode.usage.runTime.average).toBeGreaterThan(0) } + if (workerNode.usage.waitTime.aggregate == null) { + expect(workerNode.usage.waitTime.aggregate).toBeUndefined() + } else { + expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0) + } + if (workerNode.usage.waitTime.average == null) { + expect(workerNode.usage.waitTime.average).toBeUndefined() + } else { + expect(workerNode.usage.waitTime.average).toBeGreaterThan(0) + } } expect( pool.workerChoiceStrategiesContext.workerChoiceStrategies.get( @@ -1675,7 +1725,7 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategiesContext.workerChoiceStrategies.get( pool.workerChoiceStrategiesContext.defaultWorkerChoiceStrategy - ).workerNodeVirtualTaskRunTime + ).workerNodeVirtualTaskExecutionTime ).toBeGreaterThanOrEqual(0) // We need to clean up the resources after our test await pool.destroy() @@ -1714,9 +1764,9 @@ describe('Selection strategies test suite', () => { runTime: expect.objectContaining({ history: expect.any(CircularArray) }), - waitTime: { - history: new CircularArray() - }, + waitTime: expect.objectContaining({ + history: expect.any(CircularArray) + }), elu: { idle: { history: new CircularArray() @@ -1740,6 +1790,16 @@ describe('Selection strategies test suite', () => { } else { expect(workerNode.usage.runTime.median).toBeGreaterThan(0) } + if (workerNode.usage.waitTime.aggregate == null) { + expect(workerNode.usage.waitTime.aggregate).toBeUndefined() + } else { + expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0) + } + if (workerNode.usage.waitTime.median == null) { + expect(workerNode.usage.waitTime.median).toBeUndefined() + } else { + expect(workerNode.usage.waitTime.median).toBeGreaterThan(0) + } } expect( pool.workerChoiceStrategiesContext.workerChoiceStrategies.get( @@ -1754,7 +1814,7 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategiesContext.workerChoiceStrategies.get( pool.workerChoiceStrategiesContext.defaultWorkerChoiceStrategy - ).workerNodeVirtualTaskRunTime + ).workerNodeVirtualTaskExecutionTime ).toBeGreaterThanOrEqual(0) // We need to clean up the resources after our test await pool.destroy() @@ -1872,8 +1932,8 @@ describe('Selection strategies test suite', () => { median: false }, waitTime: { - aggregate: false, - average: false, + aggregate: true, + average: true, median: false }, elu: { @@ -1898,8 +1958,8 @@ describe('Selection strategies test suite', () => { median: false }, waitTime: { - aggregate: false, - average: false, + aggregate: true, + average: true, median: false }, elu: { @@ -1942,9 +2002,9 @@ describe('Selection strategies test suite', () => { runTime: expect.objectContaining({ history: expect.any(CircularArray) }), - waitTime: { - history: new CircularArray() - }, + waitTime: expect.objectContaining({ + history: expect.any(CircularArray) + }), elu: { idle: { history: new CircularArray() @@ -1958,6 +2018,26 @@ describe('Selection strategies test suite', () => { expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual( max * maxMultiplier ) + if (workerNode.usage.runTime.aggregate == null) { + expect(workerNode.usage.runTime.aggregate).toBeUndefined() + } else { + expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0) + } + if (workerNode.usage.runTime.average == null) { + expect(workerNode.usage.runTime.average).toBeUndefined() + } else { + expect(workerNode.usage.runTime.average).toBeGreaterThan(0) + } + if (workerNode.usage.waitTime.aggregate == null) { + expect(workerNode.usage.waitTime.aggregate).toBeUndefined() + } else { + expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0) + } + if (workerNode.usage.waitTime.average == null) { + expect(workerNode.usage.waitTime.average).toBeUndefined() + } else { + expect(workerNode.usage.waitTime.average).toBeGreaterThan(0) + } } expect( pool.workerChoiceStrategiesContext.workerChoiceStrategies.get( @@ -2026,9 +2106,9 @@ describe('Selection strategies test suite', () => { runTime: expect.objectContaining({ history: expect.any(CircularArray) }), - waitTime: { - history: new CircularArray() - }, + waitTime: expect.objectContaining({ + history: expect.any(CircularArray) + }), elu: { idle: { history: new CircularArray() @@ -2042,6 +2122,26 @@ describe('Selection strategies test suite', () => { expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual( max * maxMultiplier ) + if (workerNode.usage.runTime.aggregate == null) { + expect(workerNode.usage.runTime.aggregate).toBeUndefined() + } else { + expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0) + } + if (workerNode.usage.runTime.average == null) { + expect(workerNode.usage.runTime.average).toBeUndefined() + } else { + expect(workerNode.usage.runTime.average).toBeGreaterThan(0) + } + if (workerNode.usage.waitTime.aggregate == null) { + expect(workerNode.usage.waitTime.aggregate).toBeUndefined() + } else { + expect(workerNode.usage.waitTime.aggregate).toBeGreaterThan(0) + } + if (workerNode.usage.waitTime.average == null) { + expect(workerNode.usage.waitTime.average).toBeUndefined() + } else { + expect(workerNode.usage.waitTime.average).toBeGreaterThan(0) + } } expect( pool.workerChoiceStrategiesContext.workerChoiceStrategies.get( diff --git a/tests/pools/selection-strategies/weighted-round-robin-worker-choice-strategy.test.mjs b/tests/pools/selection-strategies/weighted-round-robin-worker-choice-strategy.test.mjs index 80c5ec7c..b3ea806e 100644 --- a/tests/pools/selection-strategies/weighted-round-robin-worker-choice-strategy.test.mjs +++ b/tests/pools/selection-strategies/weighted-round-robin-worker-choice-strategy.test.mjs @@ -33,7 +33,7 @@ describe('Weighted round robin strategy worker choice strategy test suite', () = expect(strategy.reset()).toBe(true) expect(strategy.nextWorkerNodeKey).toBe(0) expect(strategy.previousWorkerNodeKey).toBe(0) - expect(strategy.workerNodeVirtualTaskRunTime).toBe(0) + expect(strategy.workerNodeVirtualTaskExecutionTime).toBe(0) }) it('Verify that IWRR reset() resets internals', () => { @@ -53,6 +53,6 @@ describe('Weighted round robin strategy worker choice strategy test suite', () = expect(strategy.previousWorkerNodeKey).toBe(0) expect(strategy.roundId).toBe(0) expect(strategy.workerNodeId).toBe(0) - expect(strategy.workerNodeVirtualTaskRunTime).toBe(0) + expect(strategy.workerNodeVirtualTaskExecutionTime).toBe(0) }) })