Check that a pool have a minimum number of workers (#213)
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Mon, 22 Feb 2021 18:02:10 +0000 (19:02 +0100)
committerGitHub <noreply@github.com>
Mon, 22 Feb 2021 18:02:10 +0000 (19:02 +0100)
* Check that a pool have at least one worker,

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
* Specify return type on checkNumberOfWorkers

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
* Fix dynamic pool handling and add unit tests.

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
* Add more sanity checks to numberOfWorkers.

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
* Increase branches coverage.

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
* Renable skipped test on cluster worker.

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
* Remove wrong comment.

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
* Try to increase coverage by alternating fixed pool type.

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
* Address review comments.

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
* Sync package-lock.json

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
* Remove debug log.

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
* Fix tests (#218)

* Fix the unit test for the number of workers.

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
* Cleanups.

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
Co-authored-by: Shinigami <chrissi92@hotmail.de>
13 files changed:
benchmarks/README.md
benchmarks/versus-external-pools/functions/function-to-bench.js
package-lock.json
src/pools/abstract-pool.ts
tests/pools/abstract/abstract-pool.test.js
tests/pools/cluster/dynamic.test.js
tests/pools/cluster/fixed.test.js
tests/pools/selection-strategies.test.js
tests/pools/thread/dynamic.test.js
tests/pools/thread/fixed.test.js
tests/worker/abstract-worker.test.js
tests/worker/cluster-worker.test.js
tests/worker/thread-worker.test.js

index 5017588e4e5ea034d7ec655c2963ce1a0ee0e98d..c488a23e742de1818b3c69144301230c4764a4e2 100644 (file)
@@ -19,7 +19,7 @@ External pools with which we compared the poolifier results:
 Those are our results:
 
 - CPU Intensive task with 100k operations submitted to each pool [BENCH-100000.MD](./versus-external-pools/BENCH-100000.MD).  
-This benchmark ran on a MacBook Pro 2015, 2,2 GHz Intel Core i7 quad-core, 16 GB 1600 MHz DDR3.
+  This benchmark ran on a MacBook Pro 2015, 2,2 GHz Intel Core i7 quad-core, 16 GB 1600 MHz DDR3.
 
 > :warning: **We would need funds to run our benchmarks more often and on Cloud VMs, please consider to sponsor this project**
 
index 0c9738e62282d1486ea57141332761a0fd9705e9..23312bfcac0b26794f20c253411f066baedbe854 100644 (file)
@@ -1,5 +1,5 @@
 module.exports = function (data) {
-  if ( data.taskType === 'CPU_INTENSIVE' ) {
+  if (data.taskType === 'CPU_INTENSIVE') {
     // CPU Intensive task
     for (let i = 0; i <= 5000; i++) {
       const o = {
index 2729f7877903c03d7c317b1f0287d40b629c31bc..7634215383173a9b642529d06ec8133b86578472 100644 (file)
@@ -1,6 +1,6 @@
 {
   "name": "poolifier",
-  "version": "v2.0.0-beta.6",
+  "version": "2.0.0-beta.7",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
index c123849e6bc2aff5844185be05303f9b15bd36d6..f1ac76ed587b8059c87430edcf1bddea18264577 100644 (file)
@@ -162,6 +162,7 @@ export abstract class AbstractPool<
     if (!this.isMain()) {
       throw new Error('Cannot start a pool from a worker!')
     }
+    this.checkNumberOfWorkers(this.numberOfWorkers)
     this.checkFilePath(this.filePath)
     this.setupHook()
 
@@ -182,6 +183,24 @@ export abstract class AbstractPool<
     }
   }
 
+  private checkNumberOfWorkers (numberOfWorkers: number): void {
+    if (numberOfWorkers == null) {
+      throw new Error(
+        'Cannot instantiate a pool without specifying the number of workers'
+      )
+    } else if (!Number.isSafeInteger(numberOfWorkers)) {
+      throw new Error(
+        'Cannot instantiate a pool with a non integer number of workers'
+      )
+    } else if (numberOfWorkers < 0) {
+      throw new Error(
+        'Cannot instantiate a pool with a negative number of workers'
+      )
+    } else if (!this.isDynamic() && numberOfWorkers === 0) {
+      throw new Error('Cannot instantiate a fixed pool with no worker')
+    }
+  }
+
   /** @inheritdoc */
   public isDynamic (): boolean {
     return false
index 9b32a7e09fb6d8d9ff9b90de389b9c41d3178ce1..482ce5e39db81c3eb90b92808052a99790049873 100644 (file)
@@ -1,5 +1,5 @@
 const expect = require('expect')
-const { FixedThreadPool } = require('../../../lib/index')
+const { FixedClusterPool, FixedThreadPool } = require('../../../lib/index')
 const expectedError = new Error('Worker could not be found in tasks map')
 
 class StubPoolWithTasksMapClear extends FixedThreadPool {
@@ -18,7 +18,7 @@ describe('Abstract pool test suite', () => {
   it('Simulate worker not found during increaseWorkersTask', () => {
     const pool = new StubPoolWithTasksMapClear(
       1,
-      './tests/worker-files/cluster/testWorker.js',
+      './tests/worker-files/thread/testWorker.js',
       {
         errorHandler: e => console.error(e)
       }
@@ -31,7 +31,7 @@ describe('Abstract pool test suite', () => {
   it('Simulate worker not found during decreaseWorkersTasks', () => {
     const pool = new StubPoolWithTasksMapClear(
       1,
-      './tests/worker-files/cluster/testWorker.js',
+      './tests/worker-files/thread/testWorker.js',
       {
         errorHandler: e => console.error(e)
       }
@@ -42,23 +42,52 @@ describe('Abstract pool test suite', () => {
   })
 
   it('Simulate pool creation from a non main thread/process', () => {
-    expect(() => {
-      const pool = new StubPoolWithIsMainMethod(
-        1,
-        './tests/worker-files/cluster/testWorker.js',
-        {
-          errorHandler: e => console.error(e)
-        }
-      )
-    }).toThrowError()
+    expect(
+      () =>
+        new StubPoolWithIsMainMethod(
+          1,
+          './tests/worker-files/thread/testWorker.js',
+          {
+            errorHandler: e => console.error(e)
+          }
+        )
+    ).toThrowError(new Error('Cannot start a pool from a worker!'))
   })
 
   it('Verify that filePath is checked', () => {
-    expect(() => {
-      const pool = new StubPoolWithIsMainMethod(1).toThrowError()
-    })
-    expect(() => {
-      const pool = new StubPoolWithIsMainMethod(1, '').toThrowError()
-    })
+    expect(() => new StubPoolWithIsMainMethod(1)).toThrowError(
+      new Error('Cannot start a pool from a worker!')
+    )
+    expect(() => new StubPoolWithIsMainMethod(1, '')).toThrowError(
+      new Error('Cannot start a pool from a worker!')
+    )
+  })
+
+  it('Verify that numberOfWorkers is checked', () => {
+    expect(() => new FixedThreadPool()).toThrowError(
+      new Error(
+        'Cannot instantiate a pool without specifying the number of workers'
+      )
+    )
+  })
+
+  it('Verify that a negative number of workers is checked', () => {
+    expect(
+      () =>
+        new FixedClusterPool(-1, './tests/worker-files/cluster/testWorker.js')
+    ).toThrowError(
+      new Error('Cannot instantiate a pool with a negative number of workers')
+    )
+  })
+
+  it('Verify that a non integer number of workers is checked', () => {
+    expect(
+      () =>
+        new FixedThreadPool(0.25, './tests/worker-files/thread/testWorker.js')
+    ).toThrowError(
+      new Error(
+        'Cannot instantiate a pool with a non integer number of workers'
+      )
+    )
   })
 })
index 53a5f8d0b232e18ac26effb3ccfe466297f5458a..05d8cdd482c5edad35c3024453777e68654ae0d3 100644 (file)
@@ -56,6 +56,12 @@ describe('Dynamic cluster pool test suite', () => {
     expect(res).toBe(min)
   })
 
+  it('Validation of inputs test', () => {
+    expect(() => new DynamicClusterPool(min)).toThrowError(
+      new Error('Please specify a file with a worker implementation')
+    )
+  })
+
   it('Should work even without opts in input', async () => {
     const pool1 = new DynamicClusterPool(
       1,
@@ -103,4 +109,15 @@ describe('Dynamic cluster pool test suite', () => {
     // We need to clean up the resources after our test
     await longRunningPool.destroy()
   })
+
+  it('Verify that a pool with zero worker can be instantiated', async () => {
+    const pool = new DynamicClusterPool(
+      0,
+      max,
+      './tests/worker-files/cluster/testWorker.js'
+    )
+    expect(pool).toBeInstanceOf(DynamicClusterPool)
+    // We need to clean up the resources after our test
+    await pool.destroy()
+  })
 })
index 1137b407ac92e051096d648616912357f0ceae72..0eb21d0716c32ac19bdb321a24253a31ed0eb44a 100644 (file)
@@ -140,4 +140,11 @@ describe('Fixed cluster pool test suite', () => {
     // We need to clean up the resources after our test
     await pool1.destroy()
   })
+
+  it('Verify that a pool with zero worker fails', async () => {
+    expect(
+      () =>
+        new FixedClusterPool(0, './tests/worker-files/cluster/testWorker.js')
+    ).toThrowError(new Error('Cannot instantiate a fixed pool with no worker'))
+  })
 })
index 186dee7b03223f6f86a8c50f193cc80cb310ca93..01636b675cd76f53f78152a9f750531c4f8b32af 100644 (file)
@@ -4,7 +4,6 @@ const {
   DynamicThreadPool,
   FixedThreadPool
 } = require('../../lib/index')
-const TestUtils = require('../test-utils')
 
 describe('Selection strategies test suite', () => {
   it('Verify that WorkerChoiceStrategies enumeration provides string values', () => {
@@ -12,7 +11,7 @@ describe('Selection strategies test suite', () => {
     expect(WorkerChoiceStrategies.LESS_RECENTLY_USED).toBe('LESS_RECENTLY_USED')
   })
 
-  it('Verify LESS_RECENTLY_USED is taken', async () => {
+  it('Verify LESS_RECENTLY_USED strategy is taken', async () => {
     const max = 3
     const pool = new FixedThreadPool(
       max,
index a7f537349ed2b9d2e0a96ece08f3c1c5e2dd4964..4ee247206ba8aa0646edb0db385d3dcaa6a54dd7 100644 (file)
@@ -59,10 +59,8 @@ describe('Dynamic thread pool test suite', () => {
     expect(closedThreads).toBe(min)
   })
 
-  it('Validations test', () => {
-    expect(() => {
-      const pool1 = new DynamicThreadPool()
-    }).toThrowError(
+  it('Validation of inputs test', () => {
+    expect(() => new DynamicThreadPool(min)).toThrowError(
       new Error('Please specify a file with a worker implementation')
     )
   })
@@ -121,4 +119,15 @@ describe('Dynamic thread pool test suite', () => {
     // We need to clean up the resources after our test
     await longRunningPool.destroy()
   })
+
+  it('Verify that a pool with zero worker can be instantiated', async () => {
+    const pool = new DynamicThreadPool(
+      0,
+      max,
+      './tests/worker-files/thread/testWorker.js'
+    )
+    expect(pool).toBeInstanceOf(DynamicThreadPool)
+    // We need to clean up the resources after our test
+    await pool.destroy()
+  })
 })
index cea5502508261b85bf96cc680ab4021e81498ad7..9a2d74d30bc2f2bb194effd9494b90bf7252b6ed 100644 (file)
@@ -118,4 +118,10 @@ describe('Fixed thread pool test suite', () => {
     // We need to clean up the resources after our test
     await pool1.destroy()
   })
+
+  it('Verify that a pool with zero worker fails', async () => {
+    expect(
+      () => new FixedThreadPool(0, './tests/worker-files/thread/testWorker.js')
+    ).toThrowError(new Error('Cannot instantiate a fixed pool with no worker'))
+  })
 })
index ddb8427b82f5dd41c5273815a6dfd51446ebd45e..0c9b665ee75ae0de6a6a5fd4d910fc2bccff1fd3 100644 (file)
@@ -1,10 +1,10 @@
 const expect = require('expect')
-const { ThreadWorker } = require('../../lib')
+const { ClusterWorker } = require('../../lib')
 
 describe('Abstract worker test suite', () => {
   it('Verify that fn function is mandatory', () => {
-    expect(() => {
-      const worker = new ThreadWorker()
-    }).toThrowError()
+    expect(() => new ClusterWorker()).toThrowError(
+      new Error('fn parameter is mandatory')
+    )
   })
 })
index fc2d3442eb58fd816601cea6d8a7bc0384dd380b..5dec6076f8e34ec7f0bdf7eec42c4b5202d3d980 100644 (file)
@@ -2,8 +2,7 @@ const expect = require('expect')
 const { ClusterWorker } = require('../../lib')
 
 describe('Cluster worker test suite', () => {
-  // Skipped because ClusterWorker would be in main instead of non-main worker
-  it.skip('Verify worker has default maxInactiveTime', () => {
+  it('Verify worker has default maxInactiveTime', () => {
     const worker = new ClusterWorker(() => {})
     expect(worker.maxInactiveTime).toEqual(60_000)
   })
index dfe49655f10c7380604dd2edcfad5d30e030bf98..fd136a73a4f349e4c032398236bd426ed09f1747 100644 (file)
@@ -2,9 +2,8 @@ const expect = require('expect')
 const { ThreadWorker } = require('../../lib')
 
 let numberOfMessagesPosted = 0
-const postMessage = function (message) {
+const postMessage = function () {
   numberOfMessagesPosted++
-  console.log(message)
 }
 class SpyWorker extends ThreadWorker {
   getMainWorker () {