import type {
TaskAsyncFunction,
TaskFunction,
- TaskFunctionOperationReturnType,
+ TaskFunctionOperationResult,
TaskFunctions,
TaskSyncFunction
} from './task-functions'
+import {
+ checkTaskFunctionName,
+ checkValidTaskFunctionEntry,
+ checkValidWorkerOptions
+} from './utils'
const DEFAULT_MAX_INACTIVE_TIME = 60000
const DEFAULT_WORKER_OPTIONS: WorkerOptions = {
this.checkTaskFunctions(taskFunctions)
this.checkWorkerOptions(this.opts)
if (!this.isMain) {
+ // Should be once() but Node.js on windows has a bug that prevents it from working
this.getMainWorker().on('message', this.handleReadyMessage.bind(this))
}
}
private checkWorkerOptions (opts: WorkerOptions): void {
+ checkValidWorkerOptions(opts)
this.opts = { ...DEFAULT_WORKER_OPTIONS, ...opts }
- delete this.opts.async
- }
-
- private checkValidTaskFunction (
- 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.
+ * Checks if the `taskFunctions` parameter is passed to the constructor and valid.
*
* @param taskFunctions - The task function(s) parameter that should be checked.
*/
} else if (isPlainObject(taskFunctions)) {
let firstEntry = true
for (const [name, fn] of Object.entries(taskFunctions)) {
- this.checkValidTaskFunction(name, fn)
+ checkValidTaskFunctionEntry<Data, Response>(name, fn)
const boundFn = fn.bind(this)
if (firstEntry) {
this.taskFunctions.set(DEFAULT_TASK_NAME, boundFn)
* @param name - The name of the task function to check.
* @returns Whether the worker has a task function with the given name or not.
*/
- public hasTaskFunction (name: string): TaskFunctionOperationReturnType {
+ public hasTaskFunction (name: string): TaskFunctionOperationResult {
try {
- this.checkTaskFunctionName(name)
+ checkTaskFunctionName(name)
} catch (error) {
return { status: false, error: error as Error }
}
public addTaskFunction (
name: string,
fn: TaskFunction<Data, Response>
- ): TaskFunctionOperationReturnType {
+ ): 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'
* @param name - The name of the task function to remove.
* @returns Whether the task function existed and was removed or not.
*/
- public removeTaskFunction (name: string): TaskFunctionOperationReturnType {
+ 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'
* @param name - The name of the task function to use as default task function.
* @returns Whether the default task function was set or not.
*/
- public setDefaultTaskFunction (name: string): TaskFunctionOperationReturnType {
+ 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'
DEFAULT_TASK_NAME,
this.taskFunctions.get(name) as TaskFunction<Data, Response>
)
+ this.sendTaskFunctionNamesToMainWorker()
return { status: true }
} catch (error) {
return { status: false, error: error as Error }
}
}
- 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.
*
protected handleTaskFunctionOperationMessage (
message: MessageValue<Data>
): void {
- const { taskFunctionOperation, taskFunction, taskFunctionName } = message
- let response!: TaskFunctionOperationReturnType
- if (taskFunctionOperation === 'add') {
- response = this.addTaskFunction(
- taskFunctionName as string,
- // eslint-disable-next-line @typescript-eslint/no-implied-eval, no-new-func
- new Function(`return ${taskFunction as string}`)() as TaskFunction<
- Data,
- Response
- >
- )
- } else if (taskFunctionOperation === 'remove') {
- response = this.removeTaskFunction(taskFunctionName as string)
- } else if (taskFunctionOperation === 'default') {
- response = this.setDefaultTaskFunction(taskFunctionName as string)
+ const { taskFunctionOperation, taskFunctionName, taskFunction } = message
+ let response!: TaskFunctionOperationResult
+ switch (taskFunctionOperation) {
+ case 'add':
+ response = this.addTaskFunction(
+ taskFunctionName as string,
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval, no-new-func
+ new Function(`return ${taskFunction as string}`)() as TaskFunction<
+ Data,
+ Response
+ >
+ )
+ break
+ case 'remove':
+ response = this.removeTaskFunction(taskFunctionName as string)
+ break
+ case 'default':
+ response = this.setDefaultTaskFunction(taskFunctionName as string)
+ break
+ default:
+ response = { status: false, error: new Error('Unknown task operation') }
+ break
}
this.sendToMainWorker({
taskFunctionOperation,
taskFunctionOperationStatus: response.status,
- workerError: {
- name: taskFunctionName as string,
- message: this.handleError(response.error as Error | string)
- },
- workerId: this.id
+ taskFunctionName,
+ ...(!response.status &&
+ response?.error != null && {
+ workerError: {
+ name: taskFunctionName as string,
+ message: this.handleError(response.error as Error | string)
+ }
+ })
})
}
if (isAsyncFunction(this.opts.killHandler)) {
(this.opts.killHandler?.() as Promise<void>)
.then(() => {
- this.sendToMainWorker({ kill: 'success', workerId: this.id })
+ this.sendToMainWorker({ kill: 'success' })
return null
})
.catch(() => {
- this.sendToMainWorker({ kill: 'failure', workerId: this.id })
+ this.sendToMainWorker({ kill: 'failure' })
})
.finally(() => {
this.emitDestroy()
try {
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
this.opts.killHandler?.() as void
- this.sendToMainWorker({ kill: 'success', workerId: this.id })
+ this.sendToMainWorker({ kill: 'success' })
} catch {
- this.sendToMainWorker({ kill: 'failure', workerId: this.id })
+ this.sendToMainWorker({ kill: 'failure' })
} finally {
this.emitDestroy()
}
performance.now() - this.lastTaskTimestamp >
(this.opts.maxInactiveTime ?? DEFAULT_MAX_INACTIVE_TIME)
) {
- this.sendToMainWorker({ kill: this.opts.killBehavior, workerId: this.id })
+ this.sendToMainWorker({ kill: this.opts.killBehavior })
}
}
*/
protected sendTaskFunctionNamesToMainWorker (): void {
this.sendToMainWorker({
- taskFunctionNames: this.listTaskFunctionNames(),
- workerId: this.id
+ taskFunctionNames: this.listTaskFunctionNames()
})
}
* 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
message: `Task function '${name as string}' not found`,
data
},
- workerId: this.id,
taskId
})
return
this.sendToMainWorker({
data: res,
taskPerformance,
- workerId: this.id,
taskId
})
} catch (error) {
message: this.handleError(error as Error | string),
data
},
- workerId: this.id,
taskId
})
} finally {
this.sendToMainWorker({
data: res,
taskPerformance,
- workerId: this.id,
taskId
})
- return null
+ return undefined
})
.catch(error => {
this.sendToMainWorker({
message: this.handleError(error as Error | string),
data
},
- workerId: this.id,
taskId
})
})