From b1aae69557f4f5c524f665e92882b76f23a19866 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Sat, 19 Aug 2023 17:40:41 +0200 Subject: [PATCH] fix: fix worker choice strategy retries mechanism on some edge cases MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- CHANGELOG.md | 4 + src/pools/abstract-pool.ts | 7 +- .../abstract-worker-choice-strategy.ts | 22 ++++- .../fair-share-worker-choice-strategy.ts | 20 +++-- ...hted-round-robin-worker-choice-strategy.ts | 13 +-- .../least-busy-worker-choice-strategy.ts | 22 +++-- .../least-elu-worker-choice-strategy.ts | 22 +++-- .../least-used-worker-choice-strategy.ts | 22 +++-- .../round-robin-worker-choice-strategy.ts | 16 ++-- .../selection-strategies-types.ts | 13 ++- ...hted-round-robin-worker-choice-strategy.ts | 21 +++-- tests/pools/abstract/abstract-pool.test.js | 15 +++- .../selection-strategies.test.js | 84 ++++++++++++------- 13 files changed, 193 insertions(+), 88 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61d55fbf..3128d3fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Fix worker choice strategy retries mechanism on some edge cases. + ## [2.6.30] - 2023-08-19 ### Fixed diff --git a/src/pools/abstract-pool.ts b/src/pools/abstract-pool.ts index 183344f8..59466274 100644 --- a/src/pools/abstract-pool.ts +++ b/src/pools/abstract-pool.ts @@ -952,7 +952,7 @@ export abstract class AbstractPool< if (this.shallCreateDynamicWorker()) { const workerNodeKey = this.createAndSetupDynamicWorkerNode() if ( - this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker + this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerUsage ) { return workerNodeKey } @@ -1062,7 +1062,10 @@ export abstract class AbstractPool< workerId: workerInfo.id as number }) workerInfo.dynamic = true - if (this.workerChoiceStrategyContext.getStrategyPolicy().useDynamicWorker) { + if ( + this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerReady || + this.workerChoiceStrategyContext.getStrategyPolicy().dynamicWorkerUsage + ) { workerInfo.ready = true } this.checkAndEmitDynamicWorkerCreationEvents() diff --git a/src/pools/selection-strategies/abstract-worker-choice-strategy.ts b/src/pools/selection-strategies/abstract-worker-choice-strategy.ts index e6269422..4ed7dcae 100644 --- a/src/pools/selection-strategies/abstract-worker-choice-strategy.ts +++ b/src/pools/selection-strategies/abstract-worker-choice-strategy.ts @@ -28,11 +28,12 @@ export abstract class AbstractWorkerChoiceStrategy< /** * The next worker node key. */ - protected nextWorkerNodeKey: number = 0 + protected nextWorkerNodeKey: number | undefined = 0 /** @inheritDoc */ public readonly strategyPolicy: StrategyPolicy = { - useDynamicWorker: false + dynamicWorkerUsage: false, + dynamicWorkerReady: false } /** @inheritDoc */ @@ -94,7 +95,7 @@ export abstract class AbstractWorkerChoiceStrategy< public abstract update (workerNodeKey: number): boolean /** @inheritDoc */ - public abstract choose (): number + public abstract choose (): number | undefined /** @inheritDoc */ public abstract remove (workerNodeKey: number): boolean @@ -183,6 +184,21 @@ export abstract class AbstractWorkerChoiceStrategy< : this.pool.workerNodes[workerNodeKey].usage.elu.active?.average ?? 0 } + /** + * Assign to nextWorkerNodeKey property the chosen worker node key. + * + * @param chosenWorkerNodeKey - The chosen worker node key. + */ + protected assignChosenWorkerNodeKey ( + chosenWorkerNodeKey: number | undefined + ): void { + if (chosenWorkerNodeKey != null) { + this.nextWorkerNodeKey = chosenWorkerNodeKey + } else { + this.nextWorkerNodeKey = undefined + } + } + protected computeDefaultWorkerWeight (): number { let cpusCycleTimeWeight = 0 for (const cpu of cpus()) { 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 36d1cd4c..cfda1b0b 100644 --- a/src/pools/selection-strategies/fair-share-worker-choice-strategy.ts +++ b/src/pools/selection-strategies/fair-share-worker-choice-strategy.ts @@ -8,6 +8,7 @@ import { AbstractWorkerChoiceStrategy } from './abstract-worker-choice-strategy' import { type IWorkerChoiceStrategy, Measurements, + type StrategyPolicy, type TaskStatisticsRequirements, type WorkerChoiceStrategyOptions } from './selection-strategies-types' @@ -27,6 +28,12 @@ export class FairShareWorkerChoiceStrategy< > extends AbstractWorkerChoiceStrategy implements IWorkerChoiceStrategy { + /** @inheritDoc */ + public readonly strategyPolicy: StrategyPolicy = { + dynamicWorkerUsage: false, + dynamicWorkerReady: true + } + /** @inheritDoc */ public readonly taskStatisticsRequirements: TaskStatisticsRequirements = { runTime: { @@ -69,8 +76,10 @@ export class FairShareWorkerChoiceStrategy< } /** @inheritDoc */ - public choose (): number { - return this.fairShareNextWorkerNodeKey() + public choose (): number | undefined { + const chosenWorkerNodeKey = this.fairShareNextWorkerNodeKey() + this.assignChosenWorkerNodeKey(chosenWorkerNodeKey) + return this.nextWorkerNodeKey } /** @inheritDoc */ @@ -79,8 +88,9 @@ export class FairShareWorkerChoiceStrategy< return true } - private fairShareNextWorkerNodeKey (): number { + private fairShareNextWorkerNodeKey (): number | undefined { let minWorkerVirtualTaskEndTimestamp = Infinity + let chosenWorkerNodeKey: number | undefined for (const [workerNodeKey] of this.pool.workerNodes.entries()) { if (this.workersVirtualTaskEndTimestamp[workerNodeKey] == null) { this.computeWorkerVirtualTaskEndTimestamp(workerNodeKey) @@ -92,10 +102,10 @@ export class FairShareWorkerChoiceStrategy< workerVirtualTaskEndTimestamp < minWorkerVirtualTaskEndTimestamp ) { minWorkerVirtualTaskEndTimestamp = workerVirtualTaskEndTimestamp - this.nextWorkerNodeKey = workerNodeKey + chosenWorkerNodeKey = workerNodeKey } } - return this.nextWorkerNodeKey + return chosenWorkerNodeKey } /** 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 c45d6e0b..cdbfbee5 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 @@ -24,7 +24,8 @@ export class InterleavedWeightedRoundRobinWorkerChoiceStrategy< implements IWorkerChoiceStrategy { /** @inheritDoc */ public readonly strategyPolicy: StrategyPolicy = { - useDynamicWorker: true + dynamicWorkerUsage: false, + dynamicWorkerReady: true } /** @@ -65,7 +66,7 @@ export class InterleavedWeightedRoundRobinWorkerChoiceStrategy< } /** @inheritDoc */ - public choose (): number { + public choose (): number | undefined { let roundId: number | undefined let workerNodeId: number | undefined for ( @@ -74,7 +75,7 @@ export class InterleavedWeightedRoundRobinWorkerChoiceStrategy< roundIndex++ ) { for ( - let workerNodeKey = this.nextWorkerNodeKey; + let workerNodeKey = this.nextWorkerNodeKey ?? 0; workerNodeKey < this.pool.workerNodes.length; workerNodeKey++ ) { @@ -90,15 +91,15 @@ export class InterleavedWeightedRoundRobinWorkerChoiceStrategy< } } } - this.roundId = roundId ?? 0 - this.nextWorkerNodeKey = workerNodeId ?? 0 + this.roundId = roundId as number + this.nextWorkerNodeKey = workerNodeId const chosenWorkerNodeKey = this.nextWorkerNodeKey if (this.nextWorkerNodeKey === this.pool.workerNodes.length - 1) { this.nextWorkerNodeKey = 0 this.roundId = this.roundId === this.roundWeights.length - 1 ? 0 : this.roundId + 1 } else { - this.nextWorkerNodeKey = this.nextWorkerNodeKey + 1 + this.nextWorkerNodeKey = (this.nextWorkerNodeKey ?? 0) + 1 } return chosenWorkerNodeKey } 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 b3e9e6ba..9ea64cb5 100644 --- a/src/pools/selection-strategies/least-busy-worker-choice-strategy.ts +++ b/src/pools/selection-strategies/least-busy-worker-choice-strategy.ts @@ -7,6 +7,7 @@ import type { IWorker } from '../worker' import { AbstractWorkerChoiceStrategy } from './abstract-worker-choice-strategy' import type { IWorkerChoiceStrategy, + StrategyPolicy, TaskStatisticsRequirements, WorkerChoiceStrategyOptions } from './selection-strategies-types' @@ -25,6 +26,12 @@ export class LeastBusyWorkerChoiceStrategy< > extends AbstractWorkerChoiceStrategy implements IWorkerChoiceStrategy { + /** @inheritDoc */ + public readonly strategyPolicy: StrategyPolicy = { + dynamicWorkerUsage: false, + dynamicWorkerReady: true + } + /** @inheritDoc */ public readonly taskStatisticsRequirements: TaskStatisticsRequirements = { runTime: { @@ -60,8 +67,10 @@ export class LeastBusyWorkerChoiceStrategy< } /** @inheritDoc */ - public choose (): number { - return this.leastBusyNextWorkerNodeKey() + public choose (): number | undefined { + const chosenWorkerNodeKey = this.leastBusyNextWorkerNodeKey() + this.assignChosenWorkerNodeKey(chosenWorkerNodeKey) + return this.nextWorkerNodeKey } /** @inheritDoc */ @@ -69,23 +78,24 @@ export class LeastBusyWorkerChoiceStrategy< return true } - private leastBusyNextWorkerNodeKey (): number { + private leastBusyNextWorkerNodeKey (): number | undefined { let minTime = Infinity + let chosenWorkerNodeKey: number | undefined for (const [workerNodeKey, workerNode] of this.pool.workerNodes.entries()) { const workerTime = (workerNode.usage.runTime?.aggregate ?? 0) + (workerNode.usage.waitTime?.aggregate ?? 0) if (this.isWorkerNodeEligible(workerNodeKey) && workerTime === 0) { - this.nextWorkerNodeKey = workerNodeKey + chosenWorkerNodeKey = workerNodeKey break } else if ( this.isWorkerNodeEligible(workerNodeKey) && workerTime < minTime ) { minTime = workerTime - this.nextWorkerNodeKey = workerNodeKey + chosenWorkerNodeKey = workerNodeKey } } - return this.nextWorkerNodeKey + return chosenWorkerNodeKey } } diff --git a/src/pools/selection-strategies/least-elu-worker-choice-strategy.ts b/src/pools/selection-strategies/least-elu-worker-choice-strategy.ts index 03e6ca04..4cf2b3e4 100644 --- a/src/pools/selection-strategies/least-elu-worker-choice-strategy.ts +++ b/src/pools/selection-strategies/least-elu-worker-choice-strategy.ts @@ -7,6 +7,7 @@ import type { IWorker } from '../worker' import { AbstractWorkerChoiceStrategy } from './abstract-worker-choice-strategy' import type { IWorkerChoiceStrategy, + StrategyPolicy, TaskStatisticsRequirements, WorkerChoiceStrategyOptions } from './selection-strategies-types' @@ -25,6 +26,12 @@ export class LeastEluWorkerChoiceStrategy< > extends AbstractWorkerChoiceStrategy implements IWorkerChoiceStrategy { + /** @inheritDoc */ + public readonly strategyPolicy: StrategyPolicy = { + dynamicWorkerUsage: false, + dynamicWorkerReady: true + } + /** @inheritDoc */ public readonly taskStatisticsRequirements: TaskStatisticsRequirements = { runTime: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS, @@ -56,8 +63,10 @@ export class LeastEluWorkerChoiceStrategy< } /** @inheritDoc */ - public choose (): number { - return this.leastEluNextWorkerNodeKey() + public choose (): number | undefined { + const chosenWorkerNodeKey = this.leastEluNextWorkerNodeKey() + this.assignChosenWorkerNodeKey(chosenWorkerNodeKey) + return this.nextWorkerNodeKey } /** @inheritDoc */ @@ -65,22 +74,23 @@ export class LeastEluWorkerChoiceStrategy< return true } - private leastEluNextWorkerNodeKey (): number { + private leastEluNextWorkerNodeKey (): number | undefined { let minWorkerElu = Infinity + let chosenWorkerNodeKey: number | undefined for (const [workerNodeKey, workerNode] of this.pool.workerNodes.entries()) { const workerUsage = workerNode.usage const workerElu = workerUsage.elu?.active?.aggregate ?? 0 if (this.isWorkerNodeEligible(workerNodeKey) && workerElu === 0) { - this.nextWorkerNodeKey = workerNodeKey + chosenWorkerNodeKey = workerNodeKey break } else if ( this.isWorkerNodeEligible(workerNodeKey) && workerElu < minWorkerElu ) { minWorkerElu = workerElu - this.nextWorkerNodeKey = workerNodeKey + chosenWorkerNodeKey = workerNodeKey } } - return this.nextWorkerNodeKey + return chosenWorkerNodeKey } } 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 e72efda2..1f703321 100644 --- a/src/pools/selection-strategies/least-used-worker-choice-strategy.ts +++ b/src/pools/selection-strategies/least-used-worker-choice-strategy.ts @@ -4,6 +4,7 @@ import type { IWorker } from '../worker' import { AbstractWorkerChoiceStrategy } from './abstract-worker-choice-strategy' import type { IWorkerChoiceStrategy, + StrategyPolicy, WorkerChoiceStrategyOptions } from './selection-strategies-types' @@ -21,6 +22,12 @@ export class LeastUsedWorkerChoiceStrategy< > extends AbstractWorkerChoiceStrategy implements IWorkerChoiceStrategy { + /** @inheritDoc */ + public readonly strategyPolicy: StrategyPolicy = { + dynamicWorkerUsage: false, + dynamicWorkerReady: true + } + /** @inheritDoc */ public constructor ( pool: IPool, @@ -41,8 +48,10 @@ export class LeastUsedWorkerChoiceStrategy< } /** @inheritDoc */ - public choose (): number { - return this.leastUsedNextWorkerNodeKey() + public choose (): number | undefined { + const chosenWorkerNodeKey = this.leastUsedNextWorkerNodeKey() + this.assignChosenWorkerNodeKey(chosenWorkerNodeKey) + return this.nextWorkerNodeKey } /** @inheritDoc */ @@ -50,8 +59,9 @@ export class LeastUsedWorkerChoiceStrategy< return true } - private leastUsedNextWorkerNodeKey (): number { + private leastUsedNextWorkerNodeKey (): number | undefined { let minNumberOfTasks = Infinity + let chosenWorkerNodeKey: number | undefined for (const [workerNodeKey, workerNode] of this.pool.workerNodes.entries()) { const workerTaskStatistics = workerNode.usage.tasks const workerTasks = @@ -59,16 +69,16 @@ export class LeastUsedWorkerChoiceStrategy< workerTaskStatistics.executing + workerTaskStatistics.queued if (this.isWorkerNodeEligible(workerNodeKey) && workerTasks === 0) { - this.nextWorkerNodeKey = workerNodeKey + chosenWorkerNodeKey = workerNodeKey break } else if ( this.isWorkerNodeEligible(workerNodeKey) && workerTasks < minNumberOfTasks ) { minNumberOfTasks = workerTasks - this.nextWorkerNodeKey = workerNodeKey + chosenWorkerNodeKey = workerNodeKey } } - return this.nextWorkerNodeKey + return chosenWorkerNodeKey } } diff --git a/src/pools/selection-strategies/round-robin-worker-choice-strategy.ts b/src/pools/selection-strategies/round-robin-worker-choice-strategy.ts index 55fa8ad7..10bdf871 100644 --- a/src/pools/selection-strategies/round-robin-worker-choice-strategy.ts +++ b/src/pools/selection-strategies/round-robin-worker-choice-strategy.ts @@ -24,7 +24,8 @@ export class RoundRobinWorkerChoiceStrategy< implements IWorkerChoiceStrategy { /** @inheritDoc */ public readonly strategyPolicy: StrategyPolicy = { - useDynamicWorker: true + dynamicWorkerUsage: true, + dynamicWorkerReady: true } /** @inheritDoc */ @@ -48,11 +49,12 @@ export class RoundRobinWorkerChoiceStrategy< } /** @inheritDoc */ - public choose (): number { + public choose (): number | undefined { const chosenWorkerNodeKey = this.nextWorkerNodeKey - do { - this.roundRobinNextWorkerNodeKey() - } while (!this.isWorkerNodeEligible(this.nextWorkerNodeKey)) + this.roundRobinNextWorkerNodeKey() + if (!this.isWorkerNodeEligible(this.nextWorkerNodeKey as number)) { + this.nextWorkerNodeKey = undefined + } return chosenWorkerNodeKey } @@ -68,11 +70,11 @@ export class RoundRobinWorkerChoiceStrategy< return true } - private roundRobinNextWorkerNodeKey (): number { + private roundRobinNextWorkerNodeKey (): number | undefined { this.nextWorkerNodeKey = this.nextWorkerNodeKey === this.pool.workerNodes.length - 1 ? 0 - : this.nextWorkerNodeKey + 1 + : (this.nextWorkerNodeKey ?? 0) + 1 return this.nextWorkerNodeKey } } diff --git a/src/pools/selection-strategies/selection-strategies-types.ts b/src/pools/selection-strategies/selection-strategies-types.ts index 58f36328..4377624e 100644 --- a/src/pools/selection-strategies/selection-strategies-types.ts +++ b/src/pools/selection-strategies/selection-strategies-types.ts @@ -153,9 +153,13 @@ export interface TaskStatisticsRequirements { */ export interface StrategyPolicy { /** - * Expects direct usage of the newly created dynamic worker. + * Expects tasks execution on the newly created dynamic worker. */ - readonly useDynamicWorker: boolean + readonly dynamicWorkerUsage: boolean + /** + * Expects the newly created dynamic worker to be flagged as ready. + */ + readonly dynamicWorkerReady: boolean } /** @@ -186,10 +190,11 @@ export interface IWorkerChoiceStrategy { readonly update: (workerNodeKey: number) => boolean /** * Chooses a worker node in the pool and returns its key. + * If the worker node is not eligible, `undefined` is returned. * - * @returns The worker node key. + * @returns The worker node key or `undefined`. */ - readonly choose: () => number + readonly choose: () => number | undefined /** * Removes the worker node key from strategy internals. * 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 b5c566d5..1aab3d1c 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 @@ -29,7 +29,8 @@ export class WeightedRoundRobinWorkerChoiceStrategy< implements IWorkerChoiceStrategy { /** @inheritDoc */ public readonly strategyPolicy: StrategyPolicy = { - useDynamicWorker: true + dynamicWorkerUsage: false, + dynamicWorkerReady: true } /** @inheritDoc */ @@ -75,11 +76,12 @@ export class WeightedRoundRobinWorkerChoiceStrategy< } /** @inheritDoc */ - public choose (): number { + public choose (): number | undefined { const chosenWorkerNodeKey = this.nextWorkerNodeKey - do { - this.weightedRoundRobinNextWorkerNodeKey() - } while (!this.isWorkerNodeEligible(this.nextWorkerNodeKey)) + this.weightedRoundRobinNextWorkerNodeKey() + if (!this.isWorkerNodeEligible(this.nextWorkerNodeKey as number)) { + this.nextWorkerNodeKey = undefined + } return chosenWorkerNodeKey } @@ -96,19 +98,20 @@ export class WeightedRoundRobinWorkerChoiceStrategy< return true } - private weightedRoundRobinNextWorkerNodeKey (): number { + private weightedRoundRobinNextWorkerNodeKey (): number | undefined { const workerVirtualTaskRunTime = this.workerVirtualTaskRunTime const workerWeight = - this.opts.weights?.[this.nextWorkerNodeKey] ?? this.defaultWorkerWeight + this.opts.weights?.[this.nextWorkerNodeKey ?? 0] ?? + this.defaultWorkerWeight if (workerVirtualTaskRunTime < workerWeight) { this.workerVirtualTaskRunTime = workerVirtualTaskRunTime + - this.getWorkerTaskRunTime(this.nextWorkerNodeKey) + this.getWorkerTaskRunTime(this.nextWorkerNodeKey ?? 0) } else { this.nextWorkerNodeKey = this.nextWorkerNodeKey === this.pool.workerNodes.length - 1 ? 0 - : this.nextWorkerNodeKey + 1 + : (this.nextWorkerNodeKey ?? 0) + 1 this.workerVirtualTaskRunTime = 0 } return this.nextWorkerNodeKey diff --git a/tests/pools/abstract/abstract-pool.test.js b/tests/pools/abstract/abstract-pool.test.js index 4fd76d03..03bcce05 100644 --- a/tests/pools/abstract/abstract-pool.test.js +++ b/tests/pools/abstract/abstract-pool.test.js @@ -1,4 +1,5 @@ const { expect } = require('expect') +const sinon = require('sinon') const { DynamicClusterPool, DynamicThreadPool, @@ -900,14 +901,20 @@ describe('Abstract pool test suite', () => { }) it.skip("Verify that pool event emitter 'backPressure' event can register a callback", async () => { - const pool = new DynamicThreadPool( - Math.floor(numberOfWorkers / 2), + const pool = new FixedThreadPool( numberOfWorkers, './tests/worker-files/thread/testWorker.js', { enableTasksQueue: true } ) + for (const workerNode of pool.workerNodes) { + workerNode.hasBackPressure = sinon + .stub() + .onFirstCall() + .returns(true) + .returns(false) + } const promises = new Set() let poolBackPressure = 0 let poolInfo @@ -915,10 +922,12 @@ describe('Abstract pool test suite', () => { ++poolBackPressure poolInfo = info }) - for (let i = 0; i < Math.pow(numberOfWorkers, 2); i++) { + for (let i = 0; i < numberOfWorkers * 2; i++) { promises.add(pool.execute()) } + // console.log(pool.info.backPressure) await Promise.all(promises) + // console.log(pool.info.backPressure) expect(poolBackPressure).toBe(1) expect(poolInfo).toStrictEqual({ version, diff --git a/tests/pools/selection-strategies/selection-strategies.test.js b/tests/pools/selection-strategies/selection-strategies.test.js index 6671b577..236d34ef 100644 --- a/tests/pools/selection-strategies/selection-strategies.test.js +++ b/tests/pools/selection-strategies/selection-strategies.test.js @@ -123,7 +123,8 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy } ) expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ - useDynamicWorker: true + dynamicWorkerUsage: true, + dynamicWorkerReady: true }) await pool.destroy() pool = new DynamicThreadPool( @@ -133,7 +134,8 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy } ) expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ - useDynamicWorker: true + dynamicWorkerUsage: true, + dynamicWorkerReady: true }) // We need to clean up the resources after our test await pool.destroy() @@ -364,7 +366,8 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy } ) expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ - useDynamicWorker: false + dynamicWorkerUsage: false, + dynamicWorkerReady: true }) await pool.destroy() pool = new DynamicThreadPool( @@ -374,7 +377,8 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy } ) expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ - useDynamicWorker: false + dynamicWorkerUsage: false, + dynamicWorkerReady: true }) // We need to clean up the resources after our test await pool.destroy() @@ -537,7 +541,8 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy } ) expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ - useDynamicWorker: false + dynamicWorkerUsage: false, + dynamicWorkerReady: true }) await pool.destroy() pool = new DynamicThreadPool( @@ -547,7 +552,8 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy } ) expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ - useDynamicWorker: false + dynamicWorkerUsage: false, + dynamicWorkerReady: true }) // We need to clean up the resources after our test await pool.destroy() @@ -730,7 +736,8 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy } ) expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ - useDynamicWorker: false + dynamicWorkerUsage: false, + dynamicWorkerReady: true }) await pool.destroy() pool = new DynamicThreadPool( @@ -740,7 +747,8 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy } ) expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ - useDynamicWorker: false + dynamicWorkerUsage: false, + dynamicWorkerReady: true }) // We need to clean up the resources after our test await pool.destroy() @@ -915,7 +923,8 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy } ) expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ - useDynamicWorker: false + dynamicWorkerUsage: false, + dynamicWorkerReady: true }) await pool.destroy() pool = new DynamicThreadPool( @@ -925,7 +934,8 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy } ) expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ - useDynamicWorker: false + dynamicWorkerUsage: false, + dynamicWorkerReady: true }) // We need to clean up the resources after our test await pool.destroy() @@ -1277,7 +1287,8 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy } ) expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ - useDynamicWorker: true + dynamicWorkerUsage: false, + dynamicWorkerReady: true }) await pool.destroy() pool = new DynamicThreadPool( @@ -1287,7 +1298,8 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy } ) expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ - useDynamicWorker: true + dynamicWorkerUsage: false, + dynamicWorkerReady: true }) // We need to clean up the resources after our test await pool.destroy() @@ -1438,13 +1450,9 @@ describe('Selection strategies test suite', () => { maxQueued: 0, failed: 0 }, - runTime: { - aggregate: expect.any(Number), - maximum: expect.any(Number), - minimum: expect.any(Number), - average: expect.any(Number), + runTime: expect.objectContaining({ history: expect.any(CircularArray) - }, + }), waitTime: { history: expect.any(CircularArray) }, @@ -1461,8 +1469,16 @@ describe('Selection strategies test suite', () => { expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual( max * maxMultiplier ) - expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0) - expect(workerNode.usage.runTime.average).toBeGreaterThan(0) + 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) + } } expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( @@ -1506,13 +1522,9 @@ describe('Selection strategies test suite', () => { maxQueued: 0, failed: 0 }, - runTime: { - aggregate: expect.any(Number), - maximum: expect.any(Number), - minimum: expect.any(Number), - median: expect.any(Number), + runTime: expect.objectContaining({ history: expect.any(CircularArray) - }, + }), waitTime: { history: expect.any(CircularArray) }, @@ -1529,8 +1541,16 @@ describe('Selection strategies test suite', () => { expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual( max * maxMultiplier ) - expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0) - expect(workerNode.usage.runTime.median).toBeGreaterThan(0) + if (workerNode.usage.runTime.aggregate == null) { + expect(workerNode.usage.runTime.aggregate).toBeUndefined() + } else { + expect(workerNode.usage.runTime.aggregate).toBeGreaterThan(0) + } + if (workerNode.usage.runTime.median == null) { + expect(workerNode.usage.runTime.median).toBeUndefined() + } else { + expect(workerNode.usage.runTime.median).toBeGreaterThan(0) + } } expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( @@ -1633,7 +1653,8 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy } ) expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ - useDynamicWorker: true + dynamicWorkerUsage: false, + dynamicWorkerReady: true }) await pool.destroy() pool = new DynamicThreadPool( @@ -1643,7 +1664,8 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy } ) expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ - useDynamicWorker: true + dynamicWorkerUsage: false, + dynamicWorkerReady: true }) // We need to clean up the resources after our test await pool.destroy() @@ -1795,7 +1817,7 @@ describe('Selection strategies test suite', () => { for (const workerNode of pool.workerNodes) { expect(workerNode.usage).toStrictEqual({ tasks: { - executed: maxMultiplier, + executed: expect.any(Number), executing: 0, queued: 0, maxQueued: 0, -- 2.34.1