From 00e1bdeb5c50b0eede8fe2f72d47bf8992e4aede Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Wed, 20 Dec 2023 12:49:35 +0100 Subject: [PATCH] fix: properly account worker choice retries for WRR MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- .../typescript/http-client-pool/httpd-echo.js | 2 +- src/pools/abstract-pool.ts | 4 +- .../abstract-worker-choice-strategy.ts | 24 +--- ...hted-round-robin-worker-choice-strategy.ts | 18 +-- .../selection-strategies-types.ts | 2 +- ...hted-round-robin-worker-choice-strategy.ts | 14 +- .../worker-choice-strategy-context.ts | 22 ++- src/utils.ts | 45 +++++- tests/pools/abstract-pool.test.mjs | 80 ++++++++--- .../selection-strategies.test.mjs | 135 ++++-------------- .../worker-choice-strategy-context.test.mjs | 10 +- tests/utils.test.mjs | 32 +++-- 12 files changed, 187 insertions(+), 201 deletions(-) diff --git a/examples/typescript/http-client-pool/httpd-echo.js b/examples/typescript/http-client-pool/httpd-echo.js index 53b8ad11..81b90651 100644 --- a/examples/typescript/http-client-pool/httpd-echo.js +++ b/examples/typescript/http-client-pool/httpd-echo.js @@ -15,7 +15,7 @@ server console.info(`==== ${request.method} ${request.url} ====`) console.info('> Headers') - console.log(request.headers) + console.info(request.headers) console.info('> Body') console.info(body) diff --git a/src/pools/abstract-pool.ts b/src/pools/abstract-pool.ts index cc9408f2..4bfc3acb 100644 --- a/src/pools/abstract-pool.ts +++ b/src/pools/abstract-pool.ts @@ -130,10 +130,10 @@ export abstract class AbstractPool< /** * Constructs a new poolifier pool. * - * @param minimumNumberOfWorkers - Minimum number of workers that this pool should manage. + * @param minimumNumberOfWorkers - Minimum number of workers that this pool manages. * @param filePath - Path to the worker file. * @param opts - Options for the pool. - * @param maximumNumberOfWorkers - Maximum number of workers that this pool should manage. + * @param maximumNumberOfWorkers - Maximum number of workers that this pool manages. */ public constructor ( protected readonly minimumNumberOfWorkers: number, diff --git a/src/pools/selection-strategies/abstract-worker-choice-strategy.ts b/src/pools/selection-strategies/abstract-worker-choice-strategy.ts index b15ade84..91733b52 100644 --- a/src/pools/selection-strategies/abstract-worker-choice-strategy.ts +++ b/src/pools/selection-strategies/abstract-worker-choice-strategy.ts @@ -1,7 +1,6 @@ -import { cpus } from 'node:os' import { DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS, - getDefaultInternalWorkerChoiceStrategyOptions + buildInternalWorkerChoiceStrategyOptions } from '../../utils' import type { IPool } from '../pool' import type { IWorker } from '../worker' @@ -112,12 +111,10 @@ export abstract class AbstractWorkerChoiceStrategy< /** @inheritDoc */ public setOptions (opts: InternalWorkerChoiceStrategyOptions): void { - this.opts = { - ...getDefaultInternalWorkerChoiceStrategyOptions( - this.pool.info.maxSize + Object.keys(opts?.weights ?? {}).length - ), - ...opts - } + this.opts = buildInternalWorkerChoiceStrategyOptions( + this.pool.info.maxSize, + opts + ) this.setTaskStatisticsRequirements(this.opts) } @@ -195,15 +192,4 @@ export abstract class AbstractWorkerChoiceStrategy< protected setPreviousWorkerNodeKey (workerNodeKey: number | undefined): void { this.previousWorkerNodeKey = workerNodeKey ?? this.previousWorkerNodeKey } - - protected computeDefaultWorkerWeight (): number { - let cpusCycleTimeWeight = 0 - for (const cpu of cpus()) { - // CPU estimated cycle time - const numberOfDigits = cpu.speed.toString().length - 1 - const cpuCycleTime = 1 / (cpu.speed / Math.pow(10, numberOfDigits)) - cpusCycleTimeWeight += cpuCycleTime * Math.pow(10, numberOfDigits) - } - return Math.round(cpusCycleTimeWeight / cpus().length) - } } 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 8ccb5f78..0f718e98 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 @@ -37,14 +37,10 @@ export class InterleavedWeightedRoundRobinWorkerChoiceStrategy< * Round id. */ private roundId: number = 0 - /** - * Default worker weight. - */ - private readonly defaultWorkerWeight: number /** * Round weights. */ - private roundWeights: number[] + private roundWeights!: number[] /** * Worker node id. */ @@ -60,9 +56,7 @@ export class InterleavedWeightedRoundRobinWorkerChoiceStrategy< opts: InternalWorkerChoiceStrategyOptions ) { super(pool, opts) - this.setTaskStatisticsRequirements(this.opts) - this.defaultWorkerWeight = this.computeDefaultWorkerWeight() - this.roundWeights = this.getRoundWeights() + this.setOptions(this.opts) } /** @inheritDoc */ @@ -99,8 +93,7 @@ export class InterleavedWeightedRoundRobinWorkerChoiceStrategy< ) { this.workerNodeVirtualTaskRunTime = 0 } - const workerWeight = - this.opts.weights?.[workerNodeKey] ?? this.defaultWorkerWeight + const workerWeight = this.opts.weights?.[workerNodeKey] as number if ( this.isWorkerNodeReady(workerNodeKey) && workerWeight >= this.roundWeights[roundIndex] && @@ -160,12 +153,9 @@ export class InterleavedWeightedRoundRobinWorkerChoiceStrategy< } private getRoundWeights (): number[] { - if (this.opts.weights == null) { - return [this.defaultWorkerWeight] - } return [ ...new Set( - Object.values(this.opts.weights) + Object.values(this.opts.weights as Record) .slice() .sort((a, b) => a - b) ) diff --git a/src/pools/selection-strategies/selection-strategies-types.ts b/src/pools/selection-strategies/selection-strategies-types.ts index 59b6a84f..1467ab4f 100644 --- a/src/pools/selection-strategies/selection-strategies-types.ts +++ b/src/pools/selection-strategies/selection-strategies-types.ts @@ -95,7 +95,7 @@ export interface WorkerChoiceStrategyOptions { * * @defaultValue Weights computed automatically given the CPU performance. */ - readonly weights?: Record + weights?: Record } /** 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 fea72350..20e58752 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 @@ -34,10 +34,6 @@ export class WeightedRoundRobinWorkerChoiceStrategy< elu: DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS } - /** - * Default worker weight. - */ - private readonly defaultWorkerWeight: number /** * Worker node virtual task runtime. */ @@ -49,8 +45,7 @@ export class WeightedRoundRobinWorkerChoiceStrategy< opts: InternalWorkerChoiceStrategyOptions ) { super(pool, opts) - this.setTaskStatisticsRequirements(this.opts) - this.defaultWorkerWeight = this.computeDefaultWorkerWeight() + this.setOptions(this.opts) } /** @inheritDoc */ @@ -94,10 +89,9 @@ export class WeightedRoundRobinWorkerChoiceStrategy< } private weightedRoundRobinNextWorkerNodeKey (): number | undefined { - const workerWeight = - this.opts.weights?.[ - this.nextWorkerNodeKey ?? this.previousWorkerNodeKey - ] ?? this.defaultWorkerWeight + const workerWeight = this.opts.weights?.[ + this.nextWorkerNodeKey ?? this.previousWorkerNodeKey + ] as number if (this.workerNodeVirtualTaskRunTime < workerWeight) { this.workerNodeVirtualTaskRunTime = this.workerNodeVirtualTaskRunTime + diff --git a/src/pools/selection-strategies/worker-choice-strategy-context.ts b/src/pools/selection-strategies/worker-choice-strategy-context.ts index 6f15daa0..9a015347 100644 --- a/src/pools/selection-strategies/worker-choice-strategy-context.ts +++ b/src/pools/selection-strategies/worker-choice-strategy-context.ts @@ -1,4 +1,4 @@ -import { getDefaultInternalWorkerChoiceStrategyOptions } from '../../utils' +import { buildInternalWorkerChoiceStrategyOptions } from '../../utils' import type { IPool } from '../pool' import type { IWorker } from '../worker' import { FairShareWorkerChoiceStrategy } from './fair-share-worker-choice-strategy' @@ -46,12 +46,10 @@ export class WorkerChoiceStrategyContext< private workerChoiceStrategy: WorkerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN, private opts?: InternalWorkerChoiceStrategyOptions ) { - this.opts = { - ...getDefaultInternalWorkerChoiceStrategyOptions( - pool.info.maxSize + Object.keys(this.opts?.weights ?? {}).length - ), - ...this.opts - } + this.opts = buildInternalWorkerChoiceStrategyOptions( + pool.info.maxSize, + this.opts + ) this.execute = this.execute.bind(this) this.workerChoiceStrategies = new Map< WorkerChoiceStrategy, @@ -233,12 +231,10 @@ export class WorkerChoiceStrategyContext< pool: IPool, opts?: InternalWorkerChoiceStrategyOptions ): void { - this.opts = { - ...getDefaultInternalWorkerChoiceStrategyOptions( - pool.info.maxSize + Object.keys(opts?.weights ?? {}).length - ), - ...opts - } + this.opts = buildInternalWorkerChoiceStrategyOptions( + pool.info.maxSize, + opts + ) for (const workerChoiceStrategy of this.workerChoiceStrategies.values()) { workerChoiceStrategy.setOptions(this.opts) } diff --git a/src/utils.ts b/src/utils.ts index 2dd3947c..20493767 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -2,6 +2,7 @@ import * as os from 'node:os' import { getRandomValues } from 'node:crypto' import { Worker as ClusterWorker } from 'node:cluster' import { Worker as ThreadWorker } from 'node:worker_threads' +import { cpus } from 'node:os' import type { InternalWorkerChoiceStrategyOptions, MeasurementStatisticsRequirements @@ -27,7 +28,7 @@ export const EMPTY_FUNCTION: () => void = Object.freeze(() => { * @param retries - The number of worker choice retries. * @returns The default worker choice strategy options. */ -export const getDefaultInternalWorkerChoiceStrategyOptions = ( +const getDefaultInternalWorkerChoiceStrategyOptions = ( retries: number ): InternalWorkerChoiceStrategyOptions => { return { @@ -280,3 +281,45 @@ export const once = ( return result } } + +const clone = (object: T): T => { + return JSON.parse(JSON.stringify(object)) as T +} + +export const buildInternalWorkerChoiceStrategyOptions = ( + poolMaxSize: number, + opts?: InternalWorkerChoiceStrategyOptions +): InternalWorkerChoiceStrategyOptions => { + opts = clone(opts ?? {}) + if (opts.weights == null) { + opts.weights = getDefaultWeights(poolMaxSize) + } + return { + ...getDefaultInternalWorkerChoiceStrategyOptions( + poolMaxSize + Object.keys(opts?.weights ?? {}).length + ), + ...opts + } +} + +const getDefaultWeights = ( + poolMaxSize: number, + defaultWorkerWeight: number = getDefaultWorkerWeight() +): Record => { + const weights: Record = {} + for (let workerNodeKey = 0; workerNodeKey < poolMaxSize; workerNodeKey++) { + weights[workerNodeKey] = defaultWorkerWeight + } + return weights +} + +const getDefaultWorkerWeight = (): number => { + let cpusCycleTimeWeight = 0 + for (const cpu of cpus()) { + // CPU estimated cycle time + const numberOfDigits = cpu.speed.toString().length - 1 + const cpuCycleTime = 1 / (cpu.speed / Math.pow(10, numberOfDigits)) + cpusCycleTimeWeight += cpuCycleTime * Math.pow(10, numberOfDigits) + } + return Math.round(cpusCycleTimeWeight / cpus().length) +} diff --git a/tests/pools/abstract-pool.test.mjs b/tests/pools/abstract-pool.test.mjs index 29f038c7..d70d017b 100644 --- a/tests/pools/abstract-pool.test.mjs +++ b/tests/pools/abstract-pool.test.mjs @@ -229,18 +229,30 @@ describe('Abstract pool test suite', () => { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN }) expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({ - retries: pool.info.maxSize, + retries: + pool.info.maxSize + + Object.keys(pool.workerChoiceStrategyContext.opts.weights).length, runTime: { median: false }, waitTime: { median: false }, - elu: { median: false } + elu: { median: false }, + weights: expect.objectContaining({ + 0: expect.any(Number), + [pool.info.maxSize - 1]: expect.any(Number) + }) }) for (const [, workerChoiceStrategy] of pool.workerChoiceStrategyContext .workerChoiceStrategies) { expect(workerChoiceStrategy.opts).toStrictEqual({ - retries: pool.info.maxSize, + retries: + pool.info.maxSize + + Object.keys(workerChoiceStrategy.opts.weights).length, runTime: { median: false }, waitTime: { median: false }, - elu: { median: false } + elu: { median: false }, + weights: expect.objectContaining({ + 0: expect.any(Number), + [pool.info.maxSize - 1]: expect.any(Number) + }) }) } await pool.destroy() @@ -459,18 +471,30 @@ describe('Abstract pool test suite', () => { ) expect(pool.opts.workerChoiceStrategyOptions).toBeUndefined() expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({ - retries: pool.info.maxSize, + retries: + pool.info.maxSize + + Object.keys(pool.workerChoiceStrategyContext.opts.weights).length, runTime: { median: false }, waitTime: { median: false }, - elu: { median: false } + elu: { median: false }, + weights: expect.objectContaining({ + 0: expect.any(Number), + [pool.info.maxSize - 1]: expect.any(Number) + }) }) for (const [, workerChoiceStrategy] of pool.workerChoiceStrategyContext .workerChoiceStrategies) { expect(workerChoiceStrategy.opts).toStrictEqual({ - retries: pool.info.maxSize, + retries: + pool.info.maxSize + + Object.keys(workerChoiceStrategy.opts.weights).length, runTime: { median: false }, waitTime: { median: false }, - elu: { median: false } + elu: { median: false }, + weights: expect.objectContaining({ + 0: expect.any(Number), + [pool.info.maxSize - 1]: expect.any(Number) + }) }) } expect( @@ -501,18 +525,30 @@ describe('Abstract pool test suite', () => { elu: { median: true } }) expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({ - retries: pool.info.maxSize, + retries: + pool.info.maxSize + + Object.keys(pool.workerChoiceStrategyContext.opts.weights).length, runTime: { median: true }, waitTime: { median: false }, - elu: { median: true } + elu: { median: true }, + weights: expect.objectContaining({ + 0: expect.any(Number), + [pool.info.maxSize - 1]: expect.any(Number) + }) }) for (const [, workerChoiceStrategy] of pool.workerChoiceStrategyContext .workerChoiceStrategies) { expect(workerChoiceStrategy.opts).toStrictEqual({ - retries: pool.info.maxSize, + retries: + pool.info.maxSize + + Object.keys(workerChoiceStrategy.opts.weights).length, runTime: { median: true }, waitTime: { median: false }, - elu: { median: true } + elu: { median: true }, + weights: expect.objectContaining({ + 0: expect.any(Number), + [pool.info.maxSize - 1]: expect.any(Number) + }) }) } expect( @@ -543,18 +579,30 @@ describe('Abstract pool test suite', () => { elu: { median: false } }) expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({ - retries: pool.info.maxSize, + retries: + pool.info.maxSize + + Object.keys(pool.workerChoiceStrategyContext.opts.weights).length, runTime: { median: false }, waitTime: { median: false }, - elu: { median: false } + elu: { median: false }, + weights: expect.objectContaining({ + 0: expect.any(Number), + [pool.info.maxSize - 1]: expect.any(Number) + }) }) for (const [, workerChoiceStrategy] of pool.workerChoiceStrategyContext .workerChoiceStrategies) { expect(workerChoiceStrategy.opts).toStrictEqual({ - retries: pool.info.maxSize, + retries: + pool.info.maxSize + + Object.keys(workerChoiceStrategy.opts.weights).length, runTime: { median: false }, waitTime: { median: false }, - elu: { median: false } + elu: { median: false }, + weights: expect.objectContaining({ + 0: expect.any(Number), + [pool.info.maxSize - 1]: expect.any(Number) + }) }) } expect( diff --git a/tests/pools/selection-strategies/selection-strategies.test.mjs b/tests/pools/selection-strategies/selection-strategies.test.mjs index 200e83c7..9ee22fdd 100644 --- a/tests/pools/selection-strategies/selection-strategies.test.mjs +++ b/tests/pools/selection-strategies/selection-strategies.test.mjs @@ -68,10 +68,16 @@ describe('Selection strategies test suite', () => { ) expect(pool.opts.workerChoiceStrategyOptions).toBeUndefined() expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({ - retries: pool.info.maxSize, + retries: + pool.info.maxSize + + Object.keys(pool.workerChoiceStrategyContext.opts.weights).length, runTime: { median: false }, waitTime: { median: false }, - elu: { median: false } + elu: { median: false }, + weights: expect.objectContaining({ + 0: expect.any(Number), + [pool.info.maxSize - 1]: expect.any(Number) + }) }) await pool.destroy() } @@ -88,10 +94,16 @@ describe('Selection strategies test suite', () => { ) expect(pool.opts.workerChoiceStrategyOptions).toBeUndefined() expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({ - retries: pool.info.maxSize, + retries: + pool.info.maxSize + + Object.keys(pool.workerChoiceStrategyContext.opts.weights).length, runTime: { median: false }, waitTime: { median: false }, - elu: { median: false } + elu: { median: false }, + weights: expect.objectContaining({ + 0: expect.any(Number), + [pool.info.maxSize - 1]: expect.any(Number) + }) }) await pool.destroy() } @@ -116,11 +128,6 @@ describe('Selection strategies test suite', () => { if ( workerChoiceStrategy === WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN ) { - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - workerChoiceStrategy - ).defaultWorkerWeight - ).toBeGreaterThan(0) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( workerChoiceStrategy @@ -130,11 +137,6 @@ describe('Selection strategies test suite', () => { workerChoiceStrategy === WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN ) { - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - workerChoiceStrategy - ).defaultWorkerWeight - ).toBeGreaterThan(0) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( workerChoiceStrategy @@ -153,12 +155,8 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( workerChoiceStrategy - ).roundWeights - ).toStrictEqual([ - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - workerChoiceStrategy - ).defaultWorkerWeight - ]) + ).roundWeights.length + ).toBe(1) } } await pool.destroy() @@ -1639,11 +1637,6 @@ describe('Selection strategies test suite', () => { pool.workerChoiceStrategyContext.workerChoiceStrategy ).previousWorkerNodeKey ).toBe(0) - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - pool.workerChoiceStrategyContext.workerChoiceStrategy - ).defaultWorkerWeight - ).toBeGreaterThan(0) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy @@ -1718,11 +1711,6 @@ describe('Selection strategies test suite', () => { pool.workerChoiceStrategyContext.workerChoiceStrategy ).previousWorkerNodeKey ).toBe(0) - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - pool.workerChoiceStrategyContext.workerChoiceStrategy - ).defaultWorkerWeight - ).toBeGreaterThan(0) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy @@ -1802,11 +1790,6 @@ describe('Selection strategies test suite', () => { pool.workerChoiceStrategyContext.workerChoiceStrategy ).previousWorkerNodeKey ).toBe(0) - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - pool.workerChoiceStrategyContext.workerChoiceStrategy - ).defaultWorkerWeight - ).toBeGreaterThan(0) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy @@ -1832,11 +1815,6 @@ describe('Selection strategies test suite', () => { workerChoiceStrategy ).previousWorkerNodeKey ).toBeDefined() - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - workerChoiceStrategy - ).defaultWorkerWeight - ).toBeDefined() expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( workerChoiceStrategy @@ -1853,11 +1831,6 @@ describe('Selection strategies test suite', () => { pool.workerChoiceStrategyContext.workerChoiceStrategy ).previousWorkerNodeKey ).toBe(0) - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - pool.workerChoiceStrategyContext.workerChoiceStrategy - ).defaultWorkerWeight - ).toBeGreaterThan(0) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy @@ -1879,11 +1852,6 @@ describe('Selection strategies test suite', () => { workerChoiceStrategy ).previousWorkerNodeKey ).toBeDefined() - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - workerChoiceStrategy - ).defaultWorkerWeight - ).toBeDefined() expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( workerChoiceStrategy @@ -1900,11 +1868,6 @@ describe('Selection strategies test suite', () => { pool.workerChoiceStrategyContext.workerChoiceStrategy ).previousWorkerNodeKey ).toBe(0) - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - pool.workerChoiceStrategyContext.workerChoiceStrategy - ).defaultWorkerWeight - ).toBeGreaterThan(0) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy @@ -2045,11 +2008,6 @@ describe('Selection strategies test suite', () => { max * maxMultiplier ) } - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - pool.workerChoiceStrategyContext.workerChoiceStrategy - ).defaultWorkerWeight - ).toBeGreaterThan(0) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy @@ -2073,12 +2031,8 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy - ).roundWeights - ).toStrictEqual([ - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - pool.workerChoiceStrategyContext.workerChoiceStrategy - ).defaultWorkerWeight - ]) + ).roundWeights.length + ).toBe(1) // We need to clean up the resources after our test await pool.destroy() }) @@ -2131,11 +2085,6 @@ describe('Selection strategies test suite', () => { max * maxMultiplier ) } - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - pool.workerChoiceStrategyContext.workerChoiceStrategy - ).defaultWorkerWeight - ).toBeGreaterThan(0) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy @@ -2159,12 +2108,8 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy - ).roundWeights - ).toStrictEqual([ - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - pool.workerChoiceStrategyContext.workerChoiceStrategy - ).defaultWorkerWeight - ]) + ).roundWeights.length + ).toBe(1) // We need to clean up the resources after our test await pool.destroy() }) @@ -2196,11 +2141,6 @@ describe('Selection strategies test suite', () => { workerChoiceStrategy ).previousWorkerNodeKey ).toBeDefined() - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - workerChoiceStrategy - ).defaultWorkerWeight - ).toBeDefined() expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( workerChoiceStrategy @@ -2230,17 +2170,8 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy - ).defaultWorkerWeight - ).toBeGreaterThan(0) - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - pool.workerChoiceStrategyContext.workerChoiceStrategy - ).roundWeights - ).toStrictEqual([ - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - pool.workerChoiceStrategyContext.workerChoiceStrategy - ).defaultWorkerWeight - ]) + ).roundWeights.length + ).toBe(1) await pool.destroy() pool = new DynamicThreadPool( min, @@ -2267,11 +2198,6 @@ describe('Selection strategies test suite', () => { workerChoiceStrategy ).previousWorkerNodeKey ).toBeDefined() - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - workerChoiceStrategy - ).defaultWorkerWeight - ).toBeDefined() expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( workerChoiceStrategy @@ -2301,17 +2227,8 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy - ).defaultWorkerWeight - ).toBeGreaterThan(0) - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - pool.workerChoiceStrategyContext.workerChoiceStrategy - ).roundWeights - ).toStrictEqual([ - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - pool.workerChoiceStrategyContext.workerChoiceStrategy - ).defaultWorkerWeight - ]) + ).roundWeights.length + ).toBe(1) // We need to clean up the resources after our test await pool.destroy() }) diff --git a/tests/pools/selection-strategies/worker-choice-strategy-context.test.mjs b/tests/pools/selection-strategies/worker-choice-strategy-context.test.mjs index f076f4dd..2b8d35d8 100644 --- a/tests/pools/selection-strategies/worker-choice-strategy-context.test.mjs +++ b/tests/pools/selection-strategies/worker-choice-strategy-context.test.mjs @@ -96,7 +96,10 @@ describe('Worker choice strategy context test suite', () => { ) expect(() => workerChoiceStrategyContext.execute()).toThrow( new Error( - `Worker node key chosen is null or undefined after ${fixedPool.info.maxSize} retries` + `Worker node key chosen is null or undefined after ${ + fixedPool.info.maxSize + + Object.keys(workerChoiceStrategyContext.opts.weights).length + } retries` ) ) const workerChoiceStrategyNullStub = createStubInstance( @@ -112,7 +115,10 @@ describe('Worker choice strategy context test suite', () => { ) expect(() => workerChoiceStrategyContext.execute()).toThrow( new Error( - `Worker node key chosen is null or undefined after ${fixedPool.info.maxSize} retries` + `Worker node key chosen is null or undefined after ${ + fixedPool.info.maxSize + + Object.keys(workerChoiceStrategyContext.opts.weights).length + } retries` ) ) }) diff --git a/tests/utils.test.mjs b/tests/utils.test.mjs index 4b4e1e13..fd4f776b 100644 --- a/tests/utils.test.mjs +++ b/tests/utils.test.mjs @@ -9,8 +9,8 @@ import { EMPTY_FUNCTION, availableParallelism, average, + buildInternalWorkerChoiceStrategyOptions, exponentialDelay, - getDefaultInternalWorkerChoiceStrategyOptions, getWorkerId, getWorkerType, isAsyncFunction, @@ -35,18 +35,6 @@ describe('Utils test suite', () => { expect(EMPTY_FUNCTION).toStrictEqual(expect.any(Function)) }) - it('Verify getDefaultInternalWorkerChoiceStrategyOptions() values', () => { - const poolMaxSize = 10 - expect( - getDefaultInternalWorkerChoiceStrategyOptions(poolMaxSize) - ).toStrictEqual({ - retries: poolMaxSize, - runTime: { median: false }, - waitTime: { median: false }, - elu: { median: false } - }) - }) - it('Verify DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS values', () => { expect(DEFAULT_MEASUREMENT_STATISTICS_REQUIREMENTS).toStrictEqual({ aggregate: false, @@ -243,6 +231,24 @@ describe('Utils test suite', () => { expect(max(1, 1)).toBe(1) }) + it('Verify buildInternalWorkerChoiceStrategyOptions() behavior', () => { + const poolMaxSize = 10 + const internalWorkerChoiceStrategyOptions = + buildInternalWorkerChoiceStrategyOptions(poolMaxSize) + expect(internalWorkerChoiceStrategyOptions).toStrictEqual({ + retries: + poolMaxSize + + Object.keys(internalWorkerChoiceStrategyOptions.weights).length, + runTime: { median: false }, + waitTime: { median: false }, + elu: { median: false }, + weights: expect.objectContaining({ + 0: expect.any(Number), + [poolMaxSize - 1]: expect.any(Number) + }) + }) + }) + // it('Verify once()', () => { // let called = 0 // const fn = () => ++called -- 2.34.1