feat: add less busy worker choice strategy
authorJérôme Benoit <jerome.benoit@sap.com>
Sun, 2 Apr 2023 17:59:21 +0000 (19:59 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Sun, 2 Apr 2023 17:59:21 +0000 (19:59 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
14 files changed:
CHANGELOG.md
README.md
benchmarks/internal/bench.js
benchmarks/internal/cluster/dynamic.js
benchmarks/internal/cluster/fixed.js
benchmarks/internal/thread/dynamic.js
benchmarks/internal/thread/fixed.js
src/pools/selection-strategies/less-busy-worker-choice-strategy.ts [new file with mode: 0644]
src/pools/selection-strategies/less-used-worker-choice-strategy.ts
src/pools/selection-strategies/selection-strategies-types.ts
src/pools/selection-strategies/selection-strategies-utils.ts
tests/pools/selection-strategies/selection-strategies-utils.test.js
tests/pools/selection-strategies/selection-strategies.test.js
tests/pools/selection-strategies/worker-choice-strategy-context.test.js

index 17e3ff8ada090ba79be228bfc6ae35be70f554f9..ad3c3cf79297ead2cdfcd18aff80da571fab8c4f 100644 (file)
@@ -7,11 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 
+### Added
+
+- Add `LESS_BUSY` worker choice strategy.
+
 ### Changed
 
 - Optimize worker storage in pool.
 - Optimize worker alive status check.
-- Rename worker choice strategy `LESS_RECENTLY_USED to `LESS_USED` .
+- Rename worker choice strategy `LESS_RECENTLY_USED` to `LESS_USED`.
 - Optimize `LESS_USED` worker choice strategy.
 
 ### Fixed
index a4fab9d88cff228a0f82a6effc67177c43d80b23..2adbd97daeb13ff2a2ea70ffb18f4532168989c4 100644 (file)
--- a/README.md
+++ b/README.md
@@ -164,6 +164,7 @@ Node versions >= 16.x are supported.
 
   - `WorkerChoiceStrategies.ROUND_ROBIN`: Submit tasks to worker in a round robbin fashion
   - `WorkerChoiceStrategies.LESS_USED`: Submit tasks to the less used worker
+  - `WorkerChoiceStrategies.LESS_BUSY`: Submit tasks to the less busy worker
   - `WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN` Submit tasks to worker using a weighted round robin scheduling algorithm based on tasks execution time
   - `WorkerChoiceStrategies.FAIR_SHARE`: Submit tasks to worker using a fair share tasks scheduling algorithm based on tasks execution time
 
index e88f40cf9334f5daf0ed32fb1c525c9939d7ede5..a3de2086ce674f2b09f96dfb561365ae3d832b6a 100644 (file)
@@ -2,25 +2,25 @@ const Benchmark = require('benny')
 const {
   dynamicClusterTest,
   dynamicClusterTestFairShare,
-  dynamicClusterTestLessRecentlyUsed,
+  dynamicClusterTestLessUsed,
   dynamicClusterTestWeightedRoundRobin
 } = require('./cluster/dynamic')
 const {
   fixedClusterTest,
   fixedClusterTestFairShare,
-  fixedClusterTestLessRecentlyUsed,
+  fixedClusterTestLessUsed,
   fixedClusterTestWeightedRoundRobin
 } = require('./cluster/fixed')
 const {
   dynamicThreadTest,
   dynamicThreadTestFairShare,
-  dynamicThreadTestLessRecentlyUsed,
+  dynamicThreadTestLessUsed,
   dynamicThreadTestWeightedRoundRobin
 } = require('./thread/dynamic')
 const {
   fixedThreadTest,
   fixedThreadTestFairShare,
-  fixedThreadTestLessRecentlyUsed,
+  fixedThreadTestLessUsed,
   fixedThreadTestWeightedRoundRobin
 } = require('./thread/fixed')
 
@@ -32,8 +32,8 @@ Benchmark.suite(
   Benchmark.add('Poolifier:Fixed:ThreadPool', async () => {
     await fixedThreadTest()
   }),
-  Benchmark.add('Poolifier:Fixed:ThreadPool:LessRecentlyUsed', async () => {
-    await fixedThreadTestLessRecentlyUsed()
+  Benchmark.add('Poolifier:Fixed:ThreadPool:LessUsed', async () => {
+    await fixedThreadTestLessUsed()
   }),
   Benchmark.add('Poolifier:Fixed:ThreadPool:WeightedRoundRobin', async () => {
     await fixedThreadTestWeightedRoundRobin()
@@ -44,8 +44,8 @@ Benchmark.suite(
   Benchmark.add('Poolifier:Dynamic:ThreadPool', async () => {
     await dynamicThreadTest()
   }),
-  Benchmark.add('Poolifier:Dynamic:ThreadPool:LessRecentlyUsed', async () => {
-    await dynamicThreadTestLessRecentlyUsed()
+  Benchmark.add('Poolifier:Dynamic:ThreadPool:LessUsed', async () => {
+    await dynamicThreadTestLessUsed()
   }),
   Benchmark.add('Poolifier:Dynamic:ThreadPool:WeightedRoundRobin', async () => {
     await dynamicThreadTestWeightedRoundRobin()
@@ -56,8 +56,8 @@ Benchmark.suite(
   Benchmark.add('Poolifier:Fixed:ClusterPool', async () => {
     await fixedClusterTest()
   }),
-  Benchmark.add('Poolifier:Fixed:ClusterPool:LessRecentlyUsed', async () => {
-    await fixedClusterTestLessRecentlyUsed()
+  Benchmark.add('Poolifier:Fixed:ClusterPool:LessUsed', async () => {
+    await fixedClusterTestLessUsed()
   }),
   Benchmark.add('Poolifier:Fixed:ClusterPool:WeightedRoundRobin', async () => {
     await fixedClusterTestWeightedRoundRobin
@@ -68,8 +68,8 @@ Benchmark.suite(
   Benchmark.add('Poolifier:Dynamic:ClusterPool', async () => {
     await dynamicClusterTest()
   }),
-  Benchmark.add('Poolifier:Dynamic:ClusterPool:LessRecentlyUsed', async () => {
-    await dynamicClusterTestLessRecentlyUsed()
+  Benchmark.add('Poolifier:Dynamic:ClusterPool:LessUsed', async () => {
+    await dynamicClusterTestLessUsed()
   }),
   Benchmark.add(
     'Poolifier:Dynamic:ClusterPool:WeightedRoundRobin',
index 43fa0485e9e0ff93c03a8504bf27b8c5c713c665..60ee14f6942efdf32c5d7bb8aa52e3f2250f5990 100644 (file)
@@ -13,7 +13,7 @@ const dynamicPool = new DynamicClusterPool(
   './benchmarks/internal/cluster/worker.js'
 )
 
-const dynamicPoolLessRecentlyUsed = new DynamicClusterPool(
+const dynamicPoolLessUsed = new DynamicClusterPool(
   size / 2,
   size * 3,
   './benchmarks/internal/cluster/worker.js',
@@ -40,10 +40,10 @@ async function dynamicClusterTest (
   return runPoolifierTest(dynamicPool, { tasks, workerData })
 }
 
-async function dynamicClusterTestLessRecentlyUsed (
+async function dynamicClusterTestLessUsed (
   { tasks, workerData } = { tasks: numberOfTasks, workerData: { proof: 'ok' } }
 ) {
-  return runPoolifierTest(dynamicPoolLessRecentlyUsed, { tasks, workerData })
+  return runPoolifierTest(dynamicPoolLessUsed, { tasks, workerData })
 }
 
 async function dynamicClusterTestWeightedRoundRobin (
@@ -60,7 +60,7 @@ async function dynamicClusterTestFairShare (
 
 module.exports = {
   dynamicClusterTest,
-  dynamicClusterTestLessRecentlyUsed,
+  dynamicClusterTestLessUsed,
   dynamicClusterTestWeightedRoundRobin,
   dynamicClusterTestFairShare
 }
index 211db608f4d67b21fa9de8a78266f2f483745e08..69e4a14870013bd5f3136d8ecb25309c9d93c163 100644 (file)
@@ -12,7 +12,7 @@ const fixedPool = new FixedClusterPool(
   './benchmarks/internal/cluster/worker.js'
 )
 
-const fixedPoolLessRecentlyUsed = new FixedClusterPool(
+const fixedPoolLessUsed = new FixedClusterPool(
   size,
   './benchmarks/internal/cluster/worker.js',
   { workerChoiceStrategy: WorkerChoiceStrategies.LESS_USED }
@@ -36,10 +36,10 @@ async function fixedClusterTest (
   return runPoolifierTest(fixedPool, { tasks, workerData })
 }
 
-async function fixedClusterTestLessRecentlyUsed (
+async function fixedClusterTestLessUsed (
   { tasks, workerData } = { tasks: numberOfTasks, workerData: { proof: 'ok' } }
 ) {
-  return runPoolifierTest(fixedPoolLessRecentlyUsed, { tasks, workerData })
+  return runPoolifierTest(fixedPoolLessUsed, { tasks, workerData })
 }
 
 async function fixedClusterTestWeightedRoundRobin (
@@ -56,7 +56,7 @@ async function fixedClusterTestFairShare (
 
 module.exports = {
   fixedClusterTest,
-  fixedClusterTestLessRecentlyUsed,
+  fixedClusterTestLessUsed,
   fixedClusterTestWeightedRoundRobin,
   fixedClusterTestFairShare
 }
index 79d4721585c01a9e69dbb261ad98b1b81b8a2bb2..04f18406b0394ca2c9d9e66a9af665c6b8fe735e 100644 (file)
@@ -13,7 +13,7 @@ const dynamicPool = new DynamicThreadPool(
   './benchmarks/internal/thread/worker.js'
 )
 
-const dynamicPoolLessRecentlyUsed = new DynamicThreadPool(
+const dynamicPoolLessUsed = new DynamicThreadPool(
   size / 2,
   size * 3,
   './benchmarks/internal/thread/worker.js',
@@ -40,10 +40,10 @@ async function dynamicThreadTest (
   return runPoolifierTest(dynamicPool, { tasks, workerData })
 }
 
-async function dynamicThreadTestLessRecentlyUsed (
+async function dynamicThreadTestLessUsed (
   { tasks, workerData } = { tasks: numberOfTasks, workerData: { proof: 'ok' } }
 ) {
-  return runPoolifierTest(dynamicPoolLessRecentlyUsed, { tasks, workerData })
+  return runPoolifierTest(dynamicPoolLessUsed, { tasks, workerData })
 }
 
 async function dynamicThreadTestWeightedRoundRobin (
@@ -60,7 +60,7 @@ async function dynamicThreadTestFairShare (
 
 module.exports = {
   dynamicThreadTest,
-  dynamicThreadTestLessRecentlyUsed,
+  dynamicThreadTestLessUsed,
   dynamicThreadTestWeightedRoundRobin,
   dynamicThreadTestFairShare
 }
index 2d6ee355a1f30058a76dd0d96b5d824d3c07b16b..ee4105be4dcda8512702740a703baf7080b0d5c4 100644 (file)
@@ -12,7 +12,7 @@ const fixedPool = new FixedThreadPool(
   './benchmarks/internal/thread/worker.js'
 )
 
-const fixedPoolLessRecentlyUsed = new FixedThreadPool(
+const fixedPoolLessUsed = new FixedThreadPool(
   size,
   './benchmarks/internal/thread/worker.js',
   { workerChoiceStrategy: WorkerChoiceStrategies.LESS_USED }
@@ -36,10 +36,10 @@ async function fixedThreadTest (
   return runPoolifierTest(fixedPool, { tasks, workerData })
 }
 
-async function fixedThreadTestLessRecentlyUsed (
+async function fixedThreadTestLessUsed (
   { tasks, workerData } = { tasks: numberOfTasks, workerData: { proof: 'ok' } }
 ) {
-  return runPoolifierTest(fixedPoolLessRecentlyUsed, { tasks, workerData })
+  return runPoolifierTest(fixedPoolLessUsed, { tasks, workerData })
 }
 
 async function fixedThreadTestWeightedRoundRobin (
@@ -56,7 +56,7 @@ async function fixedThreadTestFairShare (
 
 module.exports = {
   fixedThreadTest,
-  fixedThreadTestLessRecentlyUsed,
+  fixedThreadTestLessUsed,
   fixedThreadTestWeightedRoundRobin,
   fixedThreadTestFairShare
 }
diff --git a/src/pools/selection-strategies/less-busy-worker-choice-strategy.ts b/src/pools/selection-strategies/less-busy-worker-choice-strategy.ts
new file mode 100644 (file)
index 0000000..769f3fb
--- /dev/null
@@ -0,0 +1,44 @@
+import type { IPoolWorker } from '../pool-worker'
+import { AbstractWorkerChoiceStrategy } from './abstract-worker-choice-strategy'
+import type { RequiredStatistics } from './selection-strategies-types'
+
+/**
+ * Selects the less busy worker.
+ *
+ * @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 response of execution. This can only be serializable data.
+ */
+export class LessBusyWorkerChoiceStrategy<
+  Worker extends IPoolWorker,
+  Data,
+  Response
+> extends AbstractWorkerChoiceStrategy<Worker, Data, Response> {
+  /** {@inheritDoc} */
+  public readonly requiredStatistics: RequiredStatistics = {
+    runTime: true
+  }
+
+  /** {@inheritDoc} */
+  public reset (): boolean {
+    return true
+  }
+
+  /** {@inheritDoc} */
+  public choose (): Worker {
+    let minRunTime = Infinity
+    let lessBusyWorker!: Worker
+    for (const value of this.pool.workers.values()) {
+      const worker = value.worker
+      const workerRunTime = this.pool.getWorkerTasksUsage(worker)
+        ?.runTime as number
+      if (!this.isDynamicPool && workerRunTime === 0) {
+        return worker
+      } else if (workerRunTime < minRunTime) {
+        minRunTime = workerRunTime
+        lessBusyWorker = worker
+      }
+    }
+    return lessBusyWorker
+  }
+}
index f220b2c8aba228a6d6f28bae86d06f791d7c8b83..61c8fb20643319deb4f64b1e9a7054dc4ea13719 100644 (file)
@@ -21,8 +21,7 @@ export class LessUsedWorkerChoiceStrategy<
   /** {@inheritDoc} */
   public choose (): Worker {
     let minNumberOfTasks = Infinity
-    // A worker is always found because it picks the one with fewer tasks
-    let lessRecentlyUsedWorker!: Worker
+    let lessUsedWorker!: Worker
     for (const value of this.pool.workers.values()) {
       const worker = value.worker
       const tasksUsage = this.pool.getWorkerTasksUsage(worker)
@@ -32,9 +31,9 @@ export class LessUsedWorkerChoiceStrategy<
         return worker
       } else if (workerTasks < minNumberOfTasks) {
         minNumberOfTasks = workerTasks
-        lessRecentlyUsedWorker = worker
+        lessUsedWorker = worker
       }
     }
-    return lessRecentlyUsedWorker
+    return lessUsedWorker
   }
 }
index 23efd2993d64eefd07087032e8ae39be5c2f0ccd..9ae6676550be28564a12eae35f6e64ce15db640d 100644 (file)
@@ -12,6 +12,10 @@ export const WorkerChoiceStrategies = Object.freeze({
    * Less used worker selection strategy.
    */
   LESS_USED: 'LESS_USED',
+  /**
+   * Less busy worker selection strategy.
+   */
+  LESS_BUSY: 'LESS_BUSY',
   /**
    * Fair share worker selection strategy.
    */
index 75848544a295b221bad52c91a17f47fa3f4186a9..1330ec19bcf5f182df56c213715358bd4659e847 100644 (file)
@@ -1,6 +1,7 @@
 import type { IPoolInternal } from '../pool-internal'
 import type { IPoolWorker } from '../pool-worker'
 import { FairShareWorkerChoiceStrategy } from './fair-share-worker-choice-strategy'
+import { LessBusyWorkerChoiceStrategy } from './less-busy-worker-choice-strategy'
 import { LessUsedWorkerChoiceStrategy } from './less-used-worker-choice-strategy'
 import { RoundRobinWorkerChoiceStrategy } from './round-robin-worker-choice-strategy'
 import type {
@@ -30,6 +31,8 @@ export function getWorkerChoiceStrategy<
       return new RoundRobinWorkerChoiceStrategy(pool)
     case WorkerChoiceStrategies.LESS_USED:
       return new LessUsedWorkerChoiceStrategy(pool)
+    case WorkerChoiceStrategies.LESS_BUSY:
+      return new LessBusyWorkerChoiceStrategy(pool)
     case WorkerChoiceStrategies.FAIR_SHARE:
       return new FairShareWorkerChoiceStrategy(pool)
     case WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN:
index 434960403278aa4eff3af043ef5692c25e276d3c..8715074521b0144555a0e90da9556e7749068d27 100644 (file)
@@ -13,6 +13,9 @@ const {
 const {
   LessUsedWorkerChoiceStrategy
 } = require('../../../lib/pools/selection-strategies/less-used-worker-choice-strategy')
+const {
+  LessBusyWorkerChoiceStrategy
+} = require('../../../lib/pools/selection-strategies/less-busy-worker-choice-strategy')
 const {
   FairShareWorkerChoiceStrategy
 } = require('../../../lib/pools/selection-strategies/fair-share-worker-choice-strategy')
@@ -57,6 +60,14 @@ describe('Selection strategies utils test suite', () => {
     expect(strategy).toBeInstanceOf(LessUsedWorkerChoiceStrategy)
   })
 
+  it('Verify that getWorkerChoiceStrategy() can return LESS_BUSY strategy', () => {
+    const strategy = getWorkerChoiceStrategy(
+      pool,
+      WorkerChoiceStrategies.LESS_BUSY
+    )
+    expect(strategy).toBeInstanceOf(LessBusyWorkerChoiceStrategy)
+  })
+
   it('Verify that getWorkerChoiceStrategy() can return FAIR_SHARE strategy', () => {
     const strategy = getWorkerChoiceStrategy(
       pool,
index 226419475219094bdd4822c23ef16fcbdb7dbd12..ac3e27204697e10663542ab3701e67fa47340269 100644 (file)
@@ -13,6 +13,7 @@ describe('Selection strategies test suite', () => {
   it('Verify that WorkerChoiceStrategies enumeration provides string values', () => {
     expect(WorkerChoiceStrategies.ROUND_ROBIN).toBe('ROUND_ROBIN')
     expect(WorkerChoiceStrategies.LESS_USED).toBe('LESS_USED')
+    expect(WorkerChoiceStrategies.LESS_BUSY).toBe('LESS_BUSY')
     expect(WorkerChoiceStrategies.FAIR_SHARE).toBe('FAIR_SHARE')
     expect(WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN).toBe(
       'WEIGHTED_ROUND_ROBIN'
@@ -236,7 +237,7 @@ describe('Selection strategies test suite', () => {
       './tests/worker-files/thread/testWorker.js',
       { workerChoiceStrategy: WorkerChoiceStrategies.LESS_USED }
     )
-    // TODO: Create a better test to cover `LessRecentlyUsedWorkerChoiceStrategy#choose`
+    // TODO: Create a better test to cover `LessUsedWorkerChoiceStrategy#choose`
     const promises = []
     for (let i = 0; i < max * 2; i++) {
       promises.push(pool.execute())
@@ -253,7 +254,91 @@ describe('Selection strategies test suite', () => {
       './tests/worker-files/thread/testWorker.js',
       { workerChoiceStrategy: WorkerChoiceStrategies.LESS_USED }
     )
-    // TODO: Create a better test to cover `LessRecentlyUsedWorkerChoiceStrategy#choose`
+    // TODO: Create a better test to cover `LessUsedWorkerChoiceStrategy#choose`
+    const promises = []
+    for (let i = 0; i < max * 2; i++) {
+      promises.push(pool.execute())
+    }
+    await Promise.all(promises)
+    // We need to clean up the resources after our test
+    await pool.destroy()
+  })
+
+  it('Verify LESS_BUSY strategy is taken at pool creation', async () => {
+    const pool = new FixedThreadPool(
+      max,
+      './tests/worker-files/thread/testWorker.js',
+      { workerChoiceStrategy: WorkerChoiceStrategies.LESS_BUSY }
+    )
+    expect(pool.opts.workerChoiceStrategy).toBe(
+      WorkerChoiceStrategies.LESS_BUSY
+    )
+    // We need to clean up the resources after our test
+    await pool.destroy()
+  })
+
+  it('Verify LESS_BUSY strategy can be set after pool creation', async () => {
+    const pool = new FixedThreadPool(
+      max,
+      './tests/worker-files/thread/testWorker.js'
+    )
+    pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.LESS_BUSY)
+    expect(pool.opts.workerChoiceStrategy).toBe(
+      WorkerChoiceStrategies.LESS_BUSY
+    )
+    // We need to clean up the resources after our test
+    await pool.destroy()
+  })
+
+  it('Verify LESS_BUSY strategy default tasks usage statistics requirements', async () => {
+    let pool = new FixedThreadPool(
+      max,
+      './tests/worker-files/thread/testWorker.js'
+    )
+    pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.LESS_BUSY)
+    expect(
+      pool.workerChoiceStrategyContext.getWorkerChoiceStrategy()
+        .requiredStatistics.runTime
+    ).toBe(true)
+    await pool.destroy()
+    pool = new DynamicThreadPool(
+      min,
+      max,
+      './tests/worker-files/thread/testWorker.js'
+    )
+    pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.LESS_BUSY)
+    expect(
+      pool.workerChoiceStrategyContext.getWorkerChoiceStrategy()
+        .requiredStatistics.runTime
+    ).toBe(true)
+    // We need to clean up the resources after our test
+    await pool.destroy()
+  })
+
+  it('Verify LESS_BUSY strategy can be run in a fixed pool', async () => {
+    const pool = new FixedThreadPool(
+      max,
+      './tests/worker-files/thread/testWorker.js',
+      { workerChoiceStrategy: WorkerChoiceStrategies.LESS_BUSY }
+    )
+    // TODO: Create a better test to cover `LessBusyWorkerChoiceStrategy#choose`
+    const promises = []
+    for (let i = 0; i < max * 2; i++) {
+      promises.push(pool.execute())
+    }
+    await Promise.all(promises)
+    // We need to clean up the resources after our test
+    await pool.destroy()
+  })
+
+  it('Verify LESS_BUSY strategy can be run in a dynamic pool', async () => {
+    const pool = new DynamicThreadPool(
+      min,
+      max,
+      './tests/worker-files/thread/testWorker.js',
+      { workerChoiceStrategy: WorkerChoiceStrategies.LESS_BUSY }
+    )
+    // TODO: Create a better test to cover `LessBusyWorkerChoiceStrategy#choose`
     const promises = []
     for (let i = 0; i < max * 2; i++) {
       promises.push(pool.execute())
index 0079e728295907bf76ca2c6cec5a25833372eac7..9380a038800abcb246c532240717940fe735e79f 100644 (file)
@@ -14,6 +14,9 @@ const {
 const {
   LessUsedWorkerChoiceStrategy
 } = require('../../../lib/pools/selection-strategies/less-used-worker-choice-strategy')
+const {
+  LessBusyWorkerChoiceStrategy
+} = require('../../../lib/pools/selection-strategies/less-busy-worker-choice-strategy')
 const {
   FairShareWorkerChoiceStrategy
 } = require('../../../lib/pools/selection-strategies/fair-share-worker-choice-strategy')
@@ -140,6 +143,33 @@ describe('Worker choice strategy context test suite', () => {
     ).toBeInstanceOf(LessUsedWorkerChoiceStrategy)
   })
 
+  it('Verify that setWorkerChoiceStrategy() works with LESS_BUSY and fixed pool', () => {
+    const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
+      fixedPool
+    )
+    workerChoiceStrategyContext.setWorkerChoiceStrategy(
+      WorkerChoiceStrategies.LESS_BUSY
+    )
+    expect(
+      workerChoiceStrategyContext.getWorkerChoiceStrategy()
+    ).toBeInstanceOf(LessBusyWorkerChoiceStrategy)
+  })
+
+  it('Verify that setWorkerChoiceStrategy() works with LESS_BUSY and dynamic pool', () => {
+    const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
+      dynamicPool
+    )
+    workerChoiceStrategyContext.setWorkerChoiceStrategy(
+      WorkerChoiceStrategies.LESS_BUSY
+    )
+    expect(
+      workerChoiceStrategyContext.getWorkerChoiceStrategy()
+    ).toBeInstanceOf(DynamicPoolWorkerChoiceStrategy)
+    expect(
+      workerChoiceStrategyContext.getWorkerChoiceStrategy().workerChoiceStrategy
+    ).toBeInstanceOf(LessBusyWorkerChoiceStrategy)
+  })
+
   it('Verify that setWorkerChoiceStrategy() works with FAIR_SHARE and fixed pool', () => {
     const workerChoiceStrategyContext = new WorkerChoiceStrategyContext(
       fixedPool