refactor: factor out worker helpers
[poolifier.git] / src / pools / utils.ts
1 import { existsSync } from 'node:fs'
2 import { isPlainObject } from '../utils'
3 import {
4 WorkerChoiceStrategies,
5 type WorkerChoiceStrategy
6 } from './selection-strategies/selection-strategies-types'
7 import type { TasksQueueOptions } from './pool'
8 import type { IWorker } from './worker'
9
10 export const checkFilePath = (filePath: string): void => {
11 if (
12 filePath == null ||
13 typeof filePath !== 'string' ||
14 (typeof filePath === 'string' && filePath.trim().length === 0)
15 ) {
16 throw new Error('Please specify a file with a worker implementation')
17 }
18 if (!existsSync(filePath)) {
19 throw new Error(`Cannot find the worker file '${filePath}'`)
20 }
21 }
22
23 export const checkDynamicPoolSize = (min: number, max: number): void => {
24 if (max == null) {
25 throw new TypeError(
26 'Cannot instantiate a dynamic pool without specifying the maximum pool size'
27 )
28 } else if (!Number.isSafeInteger(max)) {
29 throw new TypeError(
30 'Cannot instantiate a dynamic pool with a non safe integer maximum pool size'
31 )
32 } else if (min > max) {
33 throw new RangeError(
34 'Cannot instantiate a dynamic pool with a maximum pool size inferior to the minimum pool size'
35 )
36 } else if (max === 0) {
37 throw new RangeError(
38 'Cannot instantiate a dynamic pool with a maximum pool size equal to zero'
39 )
40 } else if (min === max) {
41 throw new RangeError(
42 'Cannot instantiate a dynamic pool with a minimum pool size equal to the maximum pool size. Use a fixed pool instead'
43 )
44 }
45 }
46
47 export const checkValidWorkerChoiceStrategy = (
48 workerChoiceStrategy: WorkerChoiceStrategy
49 ): void => {
50 if (
51 workerChoiceStrategy != null &&
52 !Object.values(WorkerChoiceStrategies).includes(workerChoiceStrategy)
53 ) {
54 throw new Error(`Invalid worker choice strategy '${workerChoiceStrategy}'`)
55 }
56 }
57
58 export const checkValidTasksQueueOptions = (
59 tasksQueueOptions: TasksQueueOptions
60 ): void => {
61 if (tasksQueueOptions != null && !isPlainObject(tasksQueueOptions)) {
62 throw new TypeError('Invalid tasks queue options: must be a plain object')
63 }
64 if (
65 tasksQueueOptions?.concurrency != null &&
66 !Number.isSafeInteger(tasksQueueOptions.concurrency)
67 ) {
68 throw new TypeError(
69 'Invalid worker node tasks concurrency: must be an integer'
70 )
71 }
72 if (
73 tasksQueueOptions?.concurrency != null &&
74 tasksQueueOptions.concurrency <= 0
75 ) {
76 throw new RangeError(
77 `Invalid worker node tasks concurrency: ${tasksQueueOptions.concurrency} is a negative integer or zero`
78 )
79 }
80 if (
81 tasksQueueOptions?.size != null &&
82 !Number.isSafeInteger(tasksQueueOptions.size)
83 ) {
84 throw new TypeError(
85 'Invalid worker node tasks queue size: must be an integer'
86 )
87 }
88 if (tasksQueueOptions?.size != null && tasksQueueOptions.size <= 0) {
89 throw new RangeError(
90 `Invalid worker node tasks queue size: ${tasksQueueOptions.size} is a negative integer or zero`
91 )
92 }
93 }
94 export const checkWorkerNodeArguments = <Worker extends IWorker>(
95 worker: Worker,
96 tasksQueueBackPressureSize: number
97 ): void => {
98 if (worker == null) {
99 throw new TypeError('Cannot construct a worker node without a worker')
100 }
101 if (tasksQueueBackPressureSize == null) {
102 throw new TypeError(
103 'Cannot construct a worker node without a tasks queue back pressure size'
104 )
105 }
106 if (!Number.isSafeInteger(tasksQueueBackPressureSize)) {
107 throw new TypeError(
108 'Cannot construct a worker node with a tasks queue back pressure size that is not an integer'
109 )
110 }
111 if (tasksQueueBackPressureSize <= 0) {
112 throw new RangeError(
113 'Cannot construct a worker node with a tasks queue back pressure size that is not a positive integer'
114 )
115 }
116 }