From 9a38f99e676160c0bc7d28fe88f27b01fa31b5a1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Tue, 19 Sep 2023 23:00:51 +0200 Subject: [PATCH] refactor: factor out worker helpers MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- src/pools/utils.ts | 24 +++++++++++ src/pools/worker-node.ts | 27 +------------ src/worker/abstract-worker.ts | 75 +++++------------------------------ src/worker/utils.ts | 62 +++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 89 deletions(-) create mode 100644 src/worker/utils.ts diff --git a/src/pools/utils.ts b/src/pools/utils.ts index 4aac5cda..e534ead2 100644 --- a/src/pools/utils.ts +++ b/src/pools/utils.ts @@ -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: 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' + ) + } +} diff --git a/src/pools/worker-node.ts b/src/pools/worker-node.ts index e9680261..5a25f8d9 100644 --- a/src/pools/worker-node.ts +++ b/src/pools/worker-node.ts @@ -20,6 +20,7 @@ import { WorkerTypes, type WorkerUsage } from './worker' +import { checkWorkerNodeArguments } from './utils' /** * Worker node. @@ -57,7 +58,7 @@ implements IWorkerNode { * @param tasksQueueBackPressureSize - The tasks queue back pressure size. */ constructor (worker: Worker, tasksQueueBackPressureSize: number) { - this.checkWorkerNodeArguments(worker, tasksQueueBackPressureSize) + checkWorkerNodeArguments(worker, tasksQueueBackPressureSize) this.worker = worker this.info = this.initWorkerInfo(worker) this.usage = this.initWorkerUsage() @@ -288,28 +289,4 @@ implements IWorkerNode { } } } - - 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' - ) - } - } } diff --git a/src/worker/abstract-worker.ts b/src/worker/abstract-worker.ts index fde55a58..311a56ad 100644 --- a/src/worker/abstract-worker.ts +++ b/src/worker/abstract-worker.ts @@ -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 - ): 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(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 ): 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): void { const { name, taskId, data } = task diff --git a/src/worker/utils.ts b/src/worker/utils.ts new file mode 100644 index 00000000..f88ead7d --- /dev/null +++ b/src/worker/utils.ts @@ -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 = ( + name: string, + fn: TaskFunction +): 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') + } +} -- 2.34.1