refactor: factor out worker helpers
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Tue, 19 Sep 2023 21:00:51 +0000 (23:00 +0200)
committerJérôme Benoit <jerome.benoit@piment-noir.org>
Tue, 19 Sep 2023 21:00:51 +0000 (23:00 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@piment-noir.org>
src/pools/utils.ts
src/pools/worker-node.ts
src/worker/abstract-worker.ts
src/worker/utils.ts [new file with mode: 0644]

index 4aac5cda47d361fd723198a53ad44f254235b56c..e534ead2363947b40096c2734517a1d7c1ea3550 100644 (file)
@@ -5,6 +5,7 @@ import {
   type WorkerChoiceStrategy
 } from './selection-strategies/selection-strategies-types'
 import type { TasksQueueOptions } from './pool'
+import type { IWorker } from './worker'
 
 export const checkFilePath = (filePath: string): void => {
   if (
@@ -90,3 +91,26 @@ export const checkValidTasksQueueOptions = (
     )
   }
 }
+export const checkWorkerNodeArguments = <Worker extends IWorker>(
+  worker: Worker,
+  tasksQueueBackPressureSize: number
+): void => {
+  if (worker == null) {
+    throw new TypeError('Cannot construct a worker node without a worker')
+  }
+  if (tasksQueueBackPressureSize == null) {
+    throw new TypeError(
+      'Cannot construct a worker node without a tasks queue back pressure size'
+    )
+  }
+  if (!Number.isSafeInteger(tasksQueueBackPressureSize)) {
+    throw new TypeError(
+      'Cannot construct a worker node with a tasks queue back pressure size that is not an integer'
+    )
+  }
+  if (tasksQueueBackPressureSize <= 0) {
+    throw new RangeError(
+      'Cannot construct a worker node with a tasks queue back pressure size that is not a positive integer'
+    )
+  }
+}
index e9680261b591e26707c11c5ca868873f3ca5a6e4..5a25f8d9bf233c4afdd205bfd504a6e43be23aab 100644 (file)
@@ -20,6 +20,7 @@ import {
   WorkerTypes,
   type WorkerUsage
 } from './worker'
+import { checkWorkerNodeArguments } from './utils'
 
 /**
  * Worker node.
@@ -57,7 +58,7 @@ implements IWorkerNode<Worker, Data> {
    * @param tasksQueueBackPressureSize - The tasks queue back pressure size.
    */
   constructor (worker: Worker, tasksQueueBackPressureSize: number) {
-    this.checkWorkerNodeArguments(worker, tasksQueueBackPressureSize)
+    checkWorkerNodeArguments<Worker>(worker, tasksQueueBackPressureSize)
     this.worker = worker
     this.info = this.initWorkerInfo(worker)
     this.usage = this.initWorkerUsage()
@@ -288,28 +289,4 @@ implements IWorkerNode<Worker, Data> {
       }
     }
   }
-
-  private checkWorkerNodeArguments (
-    worker: Worker,
-    tasksQueueBackPressureSize: number
-  ): void {
-    if (worker == null) {
-      throw new TypeError('Cannot construct a worker node without a worker')
-    }
-    if (tasksQueueBackPressureSize == null) {
-      throw new TypeError(
-        'Cannot construct a worker node without a tasks queue back pressure size'
-      )
-    }
-    if (!Number.isSafeInteger(tasksQueueBackPressureSize)) {
-      throw new TypeError(
-        'Cannot construct a worker node with a tasks queue back pressure size that is not an integer'
-      )
-    }
-    if (tasksQueueBackPressureSize <= 0) {
-      throw new RangeError(
-        'Cannot construct a worker node with a tasks queue back pressure size that is not a positive integer'
-      )
-    }
-  }
 }
index fde55a588e85413d1f6bad59d0abffee25d39c73..311a56ad60e00684835e89ef0507d60f0c9d4432 100644 (file)
@@ -22,6 +22,11 @@ import type {
   TaskFunctions,
   TaskSyncFunction
 } from './task-functions'
+import {
+  checkTaskFunctionName,
+  checkValidTaskFunctionEntry,
+  checkValidWorkerOptions
+} from './utils'
 
 const DEFAULT_MAX_INACTIVE_TIME = 60000
 const DEFAULT_WORKER_OPTIONS: WorkerOptions = {
@@ -100,58 +105,10 @@ export abstract class AbstractWorker<
   }
 
   private checkWorkerOptions (opts: WorkerOptions): void {
-    if (opts != null && !isPlainObject(opts)) {
-      throw new TypeError('opts worker options parameter is not a plain object')
-    }
-    if (
-      opts?.killBehavior != null &&
-      !Object.values(KillBehaviors).includes(opts.killBehavior)
-    ) {
-      throw new TypeError(
-        `killBehavior option '${opts.killBehavior}' is not valid`
-      )
-    }
-    if (
-      opts?.maxInactiveTime != null &&
-      !Number.isSafeInteger(opts.maxInactiveTime)
-    ) {
-      throw new TypeError('maxInactiveTime option is not an integer')
-    }
-    if (opts?.maxInactiveTime != null && opts.maxInactiveTime < 5) {
-      throw new TypeError(
-        'maxInactiveTime option is not a positive integer greater or equal than 5'
-      )
-    }
-    if (opts?.killHandler != null && typeof opts.killHandler !== 'function') {
-      throw new TypeError('killHandler option is not a function')
-    }
-    if (opts?.async != null) {
-      throw new Error('async option is deprecated')
-    }
+    checkValidWorkerOptions(opts)
     this.opts = { ...DEFAULT_WORKER_OPTIONS, ...opts }
   }
 
-  private checkValidTaskFunctionEntry (
-    name: string,
-    fn: TaskFunction<Data, Response>
-  ): void {
-    if (typeof name !== 'string') {
-      throw new TypeError(
-        'A taskFunctions parameter object key is not a string'
-      )
-    }
-    if (typeof name === 'string' && name.trim().length === 0) {
-      throw new TypeError(
-        'A taskFunctions parameter object key is an empty string'
-      )
-    }
-    if (typeof fn !== 'function') {
-      throw new TypeError(
-        'A taskFunctions parameter object value is not a function'
-      )
-    }
-  }
-
   /**
    * Checks if the `taskFunctions` parameter is passed to the constructor and valid.
    *
@@ -177,7 +134,7 @@ export abstract class AbstractWorker<
     } else if (isPlainObject(taskFunctions)) {
       let firstEntry = true
       for (const [name, fn] of Object.entries(taskFunctions)) {
-        this.checkValidTaskFunctionEntry(name, fn)
+        checkValidTaskFunctionEntry<Data, Response>(name, fn)
         const boundFn = fn.bind(this)
         if (firstEntry) {
           this.taskFunctions.set(DEFAULT_TASK_NAME, boundFn)
@@ -203,7 +160,7 @@ export abstract class AbstractWorker<
    */
   public hasTaskFunction (name: string): TaskFunctionOperationResult {
     try {
-      this.checkTaskFunctionName(name)
+      checkTaskFunctionName(name)
     } catch (error) {
       return { status: false, error: error as Error }
     }
@@ -223,7 +180,7 @@ export abstract class AbstractWorker<
     fn: TaskFunction<Data, Response>
   ): TaskFunctionOperationResult {
     try {
-      this.checkTaskFunctionName(name)
+      checkTaskFunctionName(name)
       if (name === DEFAULT_TASK_NAME) {
         throw new Error(
           'Cannot add a task function with the default reserved name'
@@ -255,7 +212,7 @@ export abstract class AbstractWorker<
    */
   public removeTaskFunction (name: string): TaskFunctionOperationResult {
     try {
-      this.checkTaskFunctionName(name)
+      checkTaskFunctionName(name)
       if (name === DEFAULT_TASK_NAME) {
         throw new Error(
           'Cannot remove the task function with the default reserved name'
@@ -311,7 +268,7 @@ export abstract class AbstractWorker<
    */
   public setDefaultTaskFunction (name: string): TaskFunctionOperationResult {
     try {
-      this.checkTaskFunctionName(name)
+      checkTaskFunctionName(name)
       if (name === DEFAULT_TASK_NAME) {
         throw new Error(
           'Cannot set the default task function reserved name as the default task function'
@@ -333,15 +290,6 @@ export abstract class AbstractWorker<
     }
   }
 
-  private checkTaskFunctionName (name: string): void {
-    if (typeof name !== 'string') {
-      throw new TypeError('name parameter is not a string')
-    }
-    if (typeof name === 'string' && name.trim().length === 0) {
-      throw new TypeError('name parameter is an empty string')
-    }
-  }
-
   /**
    * Handles the ready message sent by the main worker.
    *
@@ -541,7 +489,6 @@ export abstract class AbstractWorker<
    * Runs the given task.
    *
    * @param task - The task to execute.
-   * @throws {@link https://nodejs.org/api/errors.html#class-error} If the task function is not found.
    */
   protected run (task: Task<Data>): void {
     const { name, taskId, data } = task
diff --git a/src/worker/utils.ts b/src/worker/utils.ts
new file mode 100644 (file)
index 0000000..f88ead7
--- /dev/null
@@ -0,0 +1,62 @@
+import { isPlainObject } from '../utils'
+import type { TaskFunction } from './task-functions'
+import { KillBehaviors, type WorkerOptions } from './worker-options'
+
+export const checkValidWorkerOptions = (opts: WorkerOptions): void => {
+  if (opts != null && !isPlainObject(opts)) {
+    throw new TypeError('opts worker options parameter is not a plain object')
+  }
+  if (
+    opts?.killBehavior != null &&
+    !Object.values(KillBehaviors).includes(opts.killBehavior)
+  ) {
+    throw new TypeError(
+      `killBehavior option '${opts.killBehavior}' is not valid`
+    )
+  }
+  if (
+    opts?.maxInactiveTime != null &&
+    !Number.isSafeInteger(opts.maxInactiveTime)
+  ) {
+    throw new TypeError('maxInactiveTime option is not an integer')
+  }
+  if (opts?.maxInactiveTime != null && opts.maxInactiveTime < 5) {
+    throw new TypeError(
+      'maxInactiveTime option is not a positive integer greater or equal than 5'
+    )
+  }
+  if (opts?.killHandler != null && typeof opts.killHandler !== 'function') {
+    throw new TypeError('killHandler option is not a function')
+  }
+  if (opts?.async != null) {
+    throw new Error('async option is deprecated')
+  }
+}
+
+export const checkValidTaskFunctionEntry = <Data = unknown, Response = unknown>(
+  name: string,
+  fn: TaskFunction<Data, Response>
+): void => {
+  if (typeof name !== 'string') {
+    throw new TypeError('A taskFunctions parameter object key is not a string')
+  }
+  if (typeof name === 'string' && name.trim().length === 0) {
+    throw new TypeError(
+      'A taskFunctions parameter object key is an empty string'
+    )
+  }
+  if (typeof fn !== 'function') {
+    throw new TypeError(
+      'A taskFunctions parameter object value is not a function'
+    )
+  }
+}
+
+export const checkTaskFunctionName = (name: string): void => {
+  if (typeof name !== 'string') {
+    throw new TypeError('name parameter is not a string')
+  }
+  if (typeof name === 'string' && name.trim().length === 0) {
+    throw new TypeError('name parameter is an empty string')
+  }
+}