Improvements for #161 (#169)
authorShinigami <chrissi92@hotmail.de>
Tue, 16 Feb 2021 14:57:09 +0000 (15:57 +0100)
committerGitHub <noreply@github.com>
Tue, 16 Feb 2021 14:57:09 +0000 (15:57 +0100)
21 files changed:
CHANGELOG.md
package-lock.json
src/index.ts
src/pools/cluster/dynamic.ts
src/pools/thread/dynamic.ts
src/utility-types.ts
src/worker/abstract-worker.ts
src/worker/worker-options.ts
tests/worker/cluster/asyncErrorWorker.js
tests/worker/cluster/asyncWorker.js
tests/worker/cluster/echoWorker.js
tests/worker/cluster/emptyWorker.js
tests/worker/cluster/errorWorker.js
tests/worker/cluster/longRunningWorkerHardBehavior.js
tests/worker/cluster/testWorker.js
tests/worker/thread/asyncWorker.js
tests/worker/thread/echoWorker.js
tests/worker/thread/emptyWorker.js
tests/worker/thread/errorWorker.js
tests/worker/thread/longRunningWorkerHardBehavior.js
tests/worker/thread/testWorker.js

index f70cef0a744799d8194d3f479bcf5dee97a77808..d23919efeb0da43d7e260a0564390347f62c898d 100644 (file)
@@ -13,7 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Breaking Changes
 
-- maxInactiveTime default behavior is now changed, if you want to keep the old behavior set killBehavior to HARD ( Find more details on our JSDoc ).
+- `maxInactiveTime` default behavior is now changed, if you want to keep the old behavior set `killBehavior` to `KillBehaviors.HARD`.
+  _Find more details on our JSDoc._
 
 - We changed some internal structures, but you shouldn't be too affected by them as these are internal changes.
 
index 94eef92e9a22e01febe439db20763e87a5504549..cab635a492b0c8c48e7792b9c97133458c248629 100644 (file)
       },
       "dependencies": {
         "globals": {
-          "version": "13.5.0",
-          "resolved": "https://registry.npmjs.org/globals/-/globals-13.5.0.tgz",
-          "integrity": "sha512-TMJe2Iu/qCIEFnG7IQ62C9N/iKdgX5wSvmGOVuk75+UAGDW+Yv/hH5+Ky6d/8UMqo4WCzhFCy+pHsvv09zhBoQ==",
+          "version": "13.6.0",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-13.6.0.tgz",
+          "integrity": "sha512-YFKCX0SiPg7l5oKYCJ2zZGxcXprVXHcSnVuvzrT3oSENQonVLqM5pf9fN5dLGZGyCjhw8TN8Btwe/jKnZ0pjvQ==",
           "dev": true,
           "requires": {
             "type-fest": "^0.20.2"
       "dev": true
     },
     "handlebars": {
-      "version": "4.7.6",
-      "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz",
-      "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==",
+      "version": "4.7.7",
+      "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
+      "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
       "dev": true,
       "requires": {
         "minimist": "^1.2.5",
index b64a274b87c662d65249ca52ac82250c2bad3dd0..6cc415000d1b27c19483417ad3ce9013b2b5aa59 100644 (file)
@@ -15,5 +15,5 @@ export type { ThreadWorkerWithMessageChannel } from './pools/thread/fixed'
 export { AbstractWorker } from './worker/abstract-worker'
 export { ClusterWorker } from './worker/cluster-worker'
 export { ThreadWorker } from './worker/thread-worker'
-export type { WorkerOptions } from './worker/worker-options'
-export { killBehaviorTypes } from './worker/worker-options'
+export { KillBehaviors } from './worker/worker-options'
+export type { KillBehavior, WorkerOptions } from './worker/worker-options'
index bfafd66bd0fac3d39754933a215811581815efd3..e97ab4a9be2fdbe536fd8ac5e6fa8ae65ea1b41d 100644 (file)
@@ -1,8 +1,8 @@
 import type { Worker } from 'cluster'
 import type { JSONValue } from '../../utility-types'
+import { isKillBehavior, KillBehaviors } from '../../worker/worker-options'
 import type { ClusterPoolOptions } from './fixed'
 import { FixedClusterPool } from './fixed'
-import { killBehaviorTypes } from '../../worker/worker-options'
 
 /**
  * A cluster pool with a dynamic number of workers, but a guaranteed minimum number of workers.
@@ -63,8 +63,10 @@ export class DynamicClusterPool<
     const workerCreated = this.createAndSetupWorker()
     this.registerWorkerMessageListener<Data>(workerCreated, message => {
       const tasksInProgress = this.tasks.get(workerCreated)
-      const isKillBehaviorOptionHard = message.kill === killBehaviorTypes.HARD
-      if (isKillBehaviorOptionHard || tasksInProgress === 0) {
+      if (
+        isKillBehavior(KillBehaviors.HARD, message.kill) ||
+        tasksInProgress === 0
+      ) {
         // Kill received from the worker, means that no new tasks are submitted to that worker for a while ( > maxInactiveTime)
         this.sendToWorker(workerCreated, { kill: 1 })
         void this.destroyWorker(workerCreated)
index 4a2fd5e807f1bf992155bc155a89d956616ef589..86950b43a6de1d79431a587b0d42f78e91bcb99a 100644 (file)
@@ -1,8 +1,8 @@
 import type { JSONValue } from '../../utility-types'
+import { isKillBehavior, KillBehaviors } from '../../worker/worker-options'
 import type { PoolOptions } from '../abstract-pool'
 import type { ThreadWorkerWithMessageChannel } from './fixed'
 import { FixedThreadPool } from './fixed'
-import { killBehaviorTypes } from '../../worker/worker-options'
 
 /**
  * A thread pool with a dynamic number of threads, but a guaranteed minimum number of threads.
@@ -63,8 +63,10 @@ export class DynamicThreadPool<
     const workerCreated = this.createAndSetupWorker()
     this.registerWorkerMessageListener<Data>(workerCreated, message => {
       const tasksInProgress = this.tasks.get(workerCreated)
-      const isKillBehaviorOptionHard = message.kill === killBehaviorTypes.HARD
-      if (isKillBehaviorOptionHard || tasksInProgress === 0) {
+      if (
+        isKillBehavior(KillBehaviors.HARD, message.kill) ||
+        tasksInProgress === 0
+      ) {
         // Kill received from the worker, means that no new tasks are submitted to that worker for a while ( > maxInactiveTime)
         this.sendToWorker(workerCreated, { kill: 1 })
         void this.destroyWorker(workerCreated)
index 2a2c1993c46b1d378ae23f78138c6e87f0fd9f16..d680fa16ddc7e4748a41f2e878def0384eb2e305 100644 (file)
@@ -1,7 +1,7 @@
 import type { Worker } from 'cluster'
 import type { MessagePort } from 'worker_threads'
+import type { KillBehavior } from './worker/worker-options'
 
-export type KillBehavior = 'HARD' | 'SOFT'
 /**
  * Make all properties in T non-readonly
  */
@@ -43,7 +43,7 @@ export interface MessageValue<
   /**
    * Kill code.
    */
-  readonly kill?: KillBehavior | number
+  readonly kill?: KillBehavior | 1
   /**
    * Error.
    */
index 768c8d95ee3493267163b07ca7ff332f31caa152..6aa34e8e899fda868bf0c1935b656a21d8b67629 100644 (file)
@@ -1,12 +1,12 @@
 import { AsyncResource } from 'async_hooks'
 import type { Worker } from 'cluster'
 import type { MessagePort } from 'worker_threads'
-import type { MessageValue, KillBehavior } from '../utility-types'
-import type { WorkerOptions } from './worker-options'
+import type { MessageValue } from '../utility-types'
+import type { KillBehavior, WorkerOptions } from './worker-options'
+import { KillBehaviors } from './worker-options'
 
-const defaultMaxInactiveTime = 1000 * 60
-// TODO fix this and avoid that SOFT/HARD words are replicated so much times into the project
-const defaultKillBehavior: KillBehavior = 'SOFT'
+const DEFAULT_MAX_INACTIVE_TIME = 1000 * 60
+const DEFAULT_KILL_BEHAVIOR: KillBehavior = KillBehaviors.SOFT
 
 /**
  * Base class containing some shared logic for all poolifier workers.
@@ -56,13 +56,14 @@ export abstract class AbstractWorker<
     fn: (data: Data) => Response,
     protected mainWorker?: MainWorker | null,
     public readonly opts: WorkerOptions = {
-      killBehavior: defaultKillBehavior,
-      maxInactiveTime: defaultMaxInactiveTime
+      killBehavior: DEFAULT_KILL_BEHAVIOR,
+      maxInactiveTime: DEFAULT_MAX_INACTIVE_TIME
     }
   ) {
     super(type)
-    this.killBehavior = this.opts.killBehavior ?? defaultKillBehavior
-    this.maxInactiveTime = this.opts.maxInactiveTime ?? defaultMaxInactiveTime
+    this.killBehavior = this.opts.killBehavior ?? DEFAULT_KILL_BEHAVIOR
+    this.maxInactiveTime =
+      this.opts.maxInactiveTime ?? DEFAULT_MAX_INACTIVE_TIME
     this.async = !!this.opts.async
     this.lastTask = Date.now()
     if (!fn) throw new Error('fn parameter is mandatory')
index bdad1a8d68ad59b67a202e20a00603a4f6192719..4473a97533b5c07db172d1c756ae0bce47d1d03a 100644 (file)
@@ -1,12 +1,36 @@
-import type { KillBehavior } from '../utility-types'
-
 /**
- * Kill behavior enumeration
+ * Enumeration of kill behaviors.
  */
-export const killBehaviorTypes = Object.freeze({
+export const KillBehaviors = Object.freeze({
+  /**
+   * If `currentTime - lastActiveTime` is greater than `maxInactiveTime` but a task is still running, then the worker **wont** be deleted.
+   */
   SOFT: 'SOFT',
+  /**
+   * If `lastActiveTime` is greater than `maxInactiveTime` but a task is still running, then the worker will be deleted.
+   */
   HARD: 'HARD'
-})
+} as const)
+
+/**
+ * Kill behavior.
+ */
+export type KillBehavior = keyof typeof KillBehaviors
+
+/**
+ * Detects whether the given value is a kill behavior or not.
+ *
+ * @template KB Which specific KillBehavior to test against.
+ * @param killBehavior Which kind of kill behavior to detect. Default: `KillBehaviors.HARD`.
+ * @param value Any value.
+ * @returns `true` if `value` was strictly equals to `killBehavior`, otherwise `false`.
+ */
+export function isKillBehavior<KB extends KillBehavior> (
+  killBehavior: KB,
+  value: unknown
+): value is KB {
+  return value === killBehavior
+}
 
 /**
  * Options for workers.
@@ -14,11 +38,13 @@ export const killBehaviorTypes = Object.freeze({
 export interface WorkerOptions {
   /**
    * Maximum waiting time in milliseconds for tasks.
+   *
    * After this time, newly created workers will be terminated.
    * The last active time of your worker unit will be updated when a task is submitted to a worker or when a worker terminate a task.
-   * If killBehavior is set to HARD this value represents also the timeout for the tasks that you submit to the pool,
-   * when this timeout expires your tasks is interrupted and the worker is killed if is not part of the minimum size of the pool.
-   * If killBehavior is set to SOFT your tasks have no timeout and your workers will not be terminated until your task is
+   *
+   * - If `killBehavior` is set to `KillBehaviors.HARD` this value represents also the timeout for the tasks that you submit to the pool,
+   *   when this timeout expires your tasks is interrupted and the worker is killed if is not part of the minimum size of the pool.
+   * - If `killBehavior` is set to `KillBehaviors.SOFT` your tasks have no timeout and your workers will not be terminated until your task is.
    *
    * @default 60.000 ms
    */
@@ -30,12 +56,14 @@ export interface WorkerOptions {
    */
   async?: boolean
   /**
-   * killBehavior dictates if your async unit ( worker/process ) will be deleted in case that a task is active on it.
-   * SOFT: If current time - last active time is greater than maxInactiveTime option, but a task is still running then the worker will be not deleted.
-   * HARD: If last active time is greater than maxInactiveTime option, but a task is still running then the worker will be deleted.
+   * `killBehavior` dictates if your async unit (worker/process) will be deleted in case that a task is active on it.
+   *
+   * - SOFT: If `currentTime - lastActiveTime` is greater than `maxInactiveTime` but a task is still running, then the worker **wont** be deleted.
+   * - HARD: If `lastActiveTime` is greater than `maxInactiveTime` but a task is still running, then the worker will be deleted.
+   *
    * This option only apply to the newly created workers.
    *
-   * @default SOFT
+   * @default KillBehaviors.SOFT
    */
   killBehavior?: KillBehavior
 }
index f3e0e7c8eb49c77007eafe0c7a68877f4e22df56..b9fd9016ab91801122e4cb6394b5e590377b4f3f 100644 (file)
@@ -1,5 +1,5 @@
 'use strict'
-const { ClusterWorker, killBehaviorTypes } = require('../../../lib/index')
+const { ClusterWorker, KillBehaviors } = require('../../../lib/index')
 
 async function error (data) {
   return new Promise((resolve, reject) => {
@@ -13,5 +13,5 @@ async function error (data) {
 module.exports = new ClusterWorker(error, {
   maxInactiveTime: 500,
   async: true,
-  killBehavior: killBehaviorTypes
+  killBehavior: KillBehaviors.HARD
 })
index 106df109d4daffc4f12c50c92e7079436d38df2a..b5c784dfaca6b7491b25914ceefa81a94042c44f 100644 (file)
@@ -1,5 +1,5 @@
 'use strict'
-const { ClusterWorker, killBehaviorTypes } = require('../../../lib/index')
+const { ClusterWorker, KillBehaviors } = require('../../../lib/index')
 
 async function sleep (data) {
   return new Promise((resolve, reject) => {
@@ -10,5 +10,5 @@ async function sleep (data) {
 module.exports = new ClusterWorker(sleep, {
   maxInactiveTime: 500,
   async: true,
-  killBehavior: killBehaviorTypes.HARD
+  killBehavior: KillBehaviors.HARD
 })
index 77898bacbafb70caf8cd3deb48758a49d8d2100d..054c4bb30c2d8ef2ad2ed9dd52bc5c6f9af793e2 100644 (file)
@@ -1,5 +1,5 @@
 'use strict'
-const { ClusterWorker, killBehaviorTypes } = require('../../../lib/index')
+const { ClusterWorker, KillBehaviors } = require('../../../lib/index')
 
 function echo (data) {
   return data
@@ -7,5 +7,5 @@ function echo (data) {
 
 module.exports = new ClusterWorker(echo, {
   maxInactiveTime: 500,
-  killBehavior: killBehaviorTypes.HARD
+  killBehavior: KillBehaviors.HARD
 })
index 979057c261c7837ace12ef5c43b0aa3d4f4443d9..58c55af12b8c171a12c8b430a3b32b3e2d7c0dc5 100644 (file)
@@ -1,9 +1,9 @@
 'use strict'
-const { ClusterWorker, killBehaviorTypes } = require('../../../lib/index')
+const { ClusterWorker, KillBehaviors } = require('../../../lib/index')
 
 function test (data) {}
 
 module.exports = new ClusterWorker(test, {
   maxInactiveTime: 500,
-  killBehavior: killBehaviorTypes.HARD
+  killBehavior: KillBehaviors.HARD
 })
index 02168a677b3367fbb5980cc3b9a6bf39b18da986..d6d9297ac8e5f671c3249622139c3ba0c8b8d8b6 100644 (file)
@@ -1,5 +1,5 @@
 'use strict'
-const { ClusterWorker, killBehaviorTypes } = require('../../../lib/index')
+const { ClusterWorker, KillBehaviors } = require('../../../lib/index')
 
 function error (data) {
   throw new Error('Error Message from ClusterWorker')
@@ -8,5 +8,5 @@ function error (data) {
 module.exports = new ClusterWorker(error, {
   maxInactiveTime: 500,
   async: false,
-  killBehavior: killBehaviorTypes
+  killBehavior: KillBehaviors.HARD
 })
index 4dc69525fac2746feea5891e477126d49e3f200a..04c78f4659738fa053ac67888663833d0a2eb2a1 100644 (file)
@@ -1,5 +1,5 @@
 'use strict'
-const { ClusterWorker, killBehaviorTypes } = require('../../../lib/index')
+const { ClusterWorker, KillBehaviors } = require('../../../lib/index')
 
 async function sleep (data) {
   return new Promise((resolve, reject) => {
@@ -10,5 +10,5 @@ async function sleep (data) {
 module.exports = new ClusterWorker(sleep, {
   maxInactiveTime: 500,
   async: true,
-  killBehavior: killBehaviorTypes.HARD
+  killBehavior: KillBehaviors.HARD
 })
index 9b95294bbbb92a90bb923c864046b8d4bc7b40d1..7caad9476da291f19319b981c67e8115ac0e32a7 100644 (file)
@@ -1,5 +1,5 @@
 'use strict'
-const { ClusterWorker, killBehaviorTypes } = require('../../../lib/index')
+const { ClusterWorker, KillBehaviors } = require('../../../lib/index')
 const { isMaster } = require('cluster')
 
 function test (data) {
@@ -14,5 +14,5 @@ function test (data) {
 
 module.exports = new ClusterWorker(test, {
   maxInactiveTime: 500,
-  killBehavior: killBehaviorTypes.HARD
+  killBehavior: KillBehaviors.HARD
 })
index a6a9590d44334b5d99348bccd47cb5f7a78a39d2..0bf5d244758ce100683ea9c23faf114bd03428c8 100644 (file)
@@ -1,5 +1,5 @@
 'use strict'
-const { ThreadWorker, killBehaviorTypes } = require('../../../lib/index')
+const { ThreadWorker, KillBehaviors } = require('../../../lib/index')
 
 async function sleep (data) {
   return new Promise((resolve, reject) => {
@@ -10,5 +10,5 @@ async function sleep (data) {
 module.exports = new ThreadWorker(sleep, {
   maxInactiveTime: 500,
   async: true,
-  killBehavior: killBehaviorTypes.HARD
+  killBehavior: KillBehaviors.HARD
 })
index 9471891ea0fd30a0d0740492ef6609ee3145e55c..071428c5bc5f1414b5e61718ccf605826480bf45 100644 (file)
@@ -1,5 +1,5 @@
 'use strict'
-const { ThreadWorker, killBehaviorTypes } = require('../../../lib/index')
+const { ThreadWorker, KillBehaviors } = require('../../../lib/index')
 
 function echo (data) {
   return data
@@ -7,5 +7,5 @@ function echo (data) {
 
 module.exports = new ThreadWorker(echo, {
   maxInactiveTime: 500,
-  killBehavior: killBehaviorTypes.HARD
+  killBehavior: KillBehaviors.HARD
 })
index 1787a79c16c7923f01745bd086bac6329ee78423..6a146c2653496f99238945c6648aa1dbe51ab4e2 100644 (file)
@@ -1,9 +1,9 @@
 'use strict'
-const { ThreadWorker, killBehaviorTypes } = require('../../../lib/index')
+const { ThreadWorker, KillBehaviors } = require('../../../lib/index')
 
 function test (data) {}
 
 module.exports = new ThreadWorker(test, {
   maxInactiveTime: 500,
-  killBehavior: killBehaviorTypes.HARD
+  killBehavior: KillBehaviors.HARD
 })
index 7f7fdadd6ff4fe612588d2b6fc7ecd1e27fc74db..e9f20ab8e5101120d7f51459bf338676208f404f 100644 (file)
@@ -1,5 +1,5 @@
 'use strict'
-const { ThreadWorker, killBehaviorTypes } = require('../../../lib/index')
+const { ThreadWorker, KillBehaviors } = require('../../../lib/index')
 
 function error (data) {
   throw new Error(data)
@@ -7,5 +7,5 @@ function error (data) {
 
 module.exports = new ThreadWorker(error, {
   maxInactiveTime: 500,
-  killBehavior: killBehaviorTypes.HARD
+  killBehavior: KillBehaviors.HARD
 })
index 8e3eb38a82a8863d00a2f184fac969baf8660f8b..7d9714a8140aed85399c5b53aff47a6ec5b2a002 100644 (file)
@@ -1,5 +1,5 @@
 'use strict'
-const { ThreadWorker, killBehaviorTypes } = require('../../../lib/index')
+const { ThreadWorker, KillBehaviors } = require('../../../lib/index')
 
 async function sleep (data) {
   return new Promise((resolve, reject) => {
@@ -10,5 +10,5 @@ async function sleep (data) {
 module.exports = new ThreadWorker(sleep, {
   maxInactiveTime: 500,
   async: true,
-  killBehavior: killBehaviorTypes.HARD
+  killBehavior: KillBehaviors.HARD
 })
index 7510f00bf51086c7078f1bdeed385bd13a5707d8..c70069c7269f17d2f83069554d0e3fba5d2a15e6 100644 (file)
@@ -1,5 +1,5 @@
 'use strict'
-const { ThreadWorker, killBehaviorTypes } = require('../../../lib/index')
+const { ThreadWorker, KillBehaviors } = require('../../../lib/index')
 const { isMainThread } = require('worker_threads')
 
 function test (data) {
@@ -14,5 +14,5 @@ function test (data) {
 
 module.exports = new ThreadWorker(test, {
   maxInactiveTime: 500,
-  killBehavior: killBehaviorTypes.HARD
+  killBehavior: KillBehaviors.HARD
 })