Merge dependabot/npm_and_yarn/examples/typescript/websocket-server-pool/ws-hybrid...
[poolifier.git] / src / pools / pool.ts
1 import type { ClusterSettings } from 'node:cluster'
2 import type { EventEmitterAsyncResource } from 'node:events'
3 import type { TransferListItem, WorkerOptions } from 'node:worker_threads'
4
5 import type { TaskFunctionProperties } from '../utility-types.js'
6 import type {
7 TaskFunction,
8 TaskFunctionObject
9 } from '../worker/task-functions.js'
10 import type {
11 WorkerChoiceStrategy,
12 WorkerChoiceStrategyOptions
13 } from './selection-strategies/selection-strategies-types.js'
14 import type {
15 ErrorHandler,
16 ExitHandler,
17 IWorker,
18 IWorkerNode,
19 MessageHandler,
20 OnlineHandler,
21 WorkerType
22 } from './worker.js'
23
24 /**
25 * Enumeration of pool types.
26 */
27 export const PoolTypes: Readonly<{
28 fixed: 'fixed'
29 dynamic: 'dynamic'
30 }> = Object.freeze({
31 /**
32 * Fixed pool type.
33 */
34 fixed: 'fixed',
35 /**
36 * Dynamic pool type.
37 */
38 dynamic: 'dynamic'
39 } as const)
40
41 /**
42 * Pool type.
43 */
44 export type PoolType = keyof typeof PoolTypes
45
46 /**
47 * Enumeration of pool events.
48 */
49 export const PoolEvents: Readonly<{
50 ready: 'ready'
51 busy: 'busy'
52 full: 'full'
53 empty: 'empty'
54 destroy: 'destroy'
55 error: 'error'
56 taskError: 'taskError'
57 backPressure: 'backPressure'
58 }> = Object.freeze({
59 ready: 'ready',
60 busy: 'busy',
61 full: 'full',
62 empty: 'empty',
63 destroy: 'destroy',
64 error: 'error',
65 taskError: 'taskError',
66 backPressure: 'backPressure'
67 } as const)
68
69 /**
70 * Pool event.
71 */
72 export type PoolEvent = keyof typeof PoolEvents
73
74 /**
75 * Pool information.
76 */
77 export interface PoolInfo {
78 readonly version: string
79 readonly type: PoolType
80 readonly worker: WorkerType
81 readonly started: boolean
82 readonly ready: boolean
83 readonly defaultStrategy: WorkerChoiceStrategy
84 readonly strategyRetries: number
85 readonly minSize: number
86 readonly maxSize: number
87 /** Pool utilization. */
88 readonly utilization?: number
89 /** Pool total worker nodes. */
90 readonly workerNodes: number
91 /** Pool stealing worker nodes. */
92 readonly stealingWorkerNodes?: number
93 /** Pool idle worker nodes. */
94 readonly idleWorkerNodes: number
95 /** Pool busy worker nodes. */
96 readonly busyWorkerNodes: number
97 readonly executedTasks: number
98 readonly executingTasks: number
99 readonly queuedTasks?: number
100 readonly maxQueuedTasks?: number
101 readonly backPressure?: boolean
102 readonly stolenTasks?: number
103 readonly failedTasks: number
104 readonly runTime?: {
105 readonly minimum: number
106 readonly maximum: number
107 readonly average?: number
108 readonly median?: number
109 }
110 readonly waitTime?: {
111 readonly minimum: number
112 readonly maximum: number
113 readonly average?: number
114 readonly median?: number
115 }
116 }
117
118 /**
119 * Worker node tasks queue options.
120 */
121 export interface TasksQueueOptions {
122 /**
123 * Maximum tasks queue size per worker node flagging it as back pressured.
124 *
125 * @defaultValue (pool maximum size)^2
126 */
127 readonly size?: number
128 /**
129 * Maximum number of tasks that can be executed concurrently on a worker node.
130 *
131 * @defaultValue 1
132 */
133 readonly concurrency?: number
134 /**
135 * Whether to enable task stealing on idle.
136 *
137 * @defaultValue true
138 */
139 readonly taskStealing?: boolean
140 /**
141 * Whether to enable tasks stealing under back pressure.
142 *
143 * @defaultValue false
144 */
145 readonly tasksStealingOnBackPressure?: boolean
146 /**
147 * Queued tasks finished timeout in milliseconds at worker node termination.
148 *
149 * @defaultValue 2000
150 */
151 readonly tasksFinishedTimeout?: number
152 }
153
154 /**
155 * Options for a poolifier pool.
156 *
157 * @typeParam Worker - Type of worker.
158 */
159 export interface PoolOptions<Worker extends IWorker> {
160 /**
161 * A function that will listen for online event on each worker.
162 *
163 * @defaultValue `() => {}`
164 */
165 onlineHandler?: OnlineHandler<Worker>
166 /**
167 * A function that will listen for message event on each worker.
168 *
169 * @defaultValue `() => {}`
170 */
171 messageHandler?: MessageHandler<Worker>
172 /**
173 * A function that will listen for error event on each worker.
174 *
175 * @defaultValue `() => {}`
176 */
177 errorHandler?: ErrorHandler<Worker>
178 /**
179 * A function that will listen for exit event on each worker.
180 *
181 * @defaultValue `() => {}`
182 */
183 exitHandler?: ExitHandler<Worker>
184 /**
185 * Whether to start the minimum number of workers at pool initialization.
186 *
187 * @defaultValue true
188 */
189 startWorkers?: boolean
190 /**
191 * The default worker choice strategy to use in this pool.
192 *
193 * @defaultValue WorkerChoiceStrategies.ROUND_ROBIN
194 */
195 workerChoiceStrategy?: WorkerChoiceStrategy
196 /**
197 * The worker choice strategy options.
198 */
199 workerChoiceStrategyOptions?: WorkerChoiceStrategyOptions
200 /**
201 * Restart worker on error.
202 */
203 restartWorkerOnError?: boolean
204 /**
205 * Pool events integrated with async resource emission.
206 *
207 * @defaultValue true
208 */
209 enableEvents?: boolean
210 /**
211 * Pool worker node tasks queue.
212 *
213 * @defaultValue false
214 */
215 enableTasksQueue?: boolean
216 /**
217 * Pool worker node tasks queue options.
218 */
219 tasksQueueOptions?: TasksQueueOptions
220 /**
221 * Worker options.
222 *
223 * @see https://nodejs.org/api/worker_threads.html#new-workerfilename-options
224 */
225 workerOptions?: WorkerOptions
226 /**
227 * Key/value pairs to add to worker process environment.
228 *
229 * @see https://nodejs.org/api/cluster.html#cluster_cluster_fork_env
230 */
231 env?: Record<string, unknown>
232 /**
233 * Cluster settings.
234 *
235 * @see https://nodejs.org/api/cluster.html#cluster_cluster_settings
236 */
237 settings?: ClusterSettings
238 }
239
240 /**
241 * Contract definition for a poolifier pool.
242 *
243 * @typeParam Worker - Type of worker which manages this pool.
244 * @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
245 * @typeParam Response - Type of execution response. This can only be structured-cloneable data.
246 */
247 export interface IPool<
248 Worker extends IWorker,
249 Data = unknown,
250 Response = unknown
251 > {
252 /**
253 * Pool information.
254 */
255 readonly info: PoolInfo
256 /**
257 * Pool worker nodes.
258 *
259 * @internal
260 */
261 readonly workerNodes: Array<IWorkerNode<Worker, Data>>
262 /**
263 * Pool event emitter integrated with async resource.
264 * The async tracking tooling identifier is `poolifier:<PoolType>-<WorkerType>-pool`.
265 *
266 * Events that can currently be listened to:
267 *
268 * - `'ready'`: Emitted when the number of workers created in the pool has reached the minimum size expected and are ready. If the pool is dynamic with a minimum number of workers is set to zero, this event is emitted when at least one dynamic worker is ready.
269 * - `'busy'`: Emitted when the number of workers created in the pool has reached the maximum size expected and are executing concurrently their tasks quota.
270 * - `'full'`: Emitted when the pool is dynamic and the number of workers created has reached the maximum size expected.
271 * - `'empty'`: Emitted when the pool is dynamic with a minimum number of workers set to zero and the number of workers has reached the minimum size expected.
272 * - `'destroy'`: Emitted when the pool is destroyed.
273 * - `'error'`: Emitted when an uncaught error occurs.
274 * - `'taskError'`: Emitted when an error occurs while executing a task.
275 * - `'backPressure'`: Emitted when all worker nodes have back pressure (i.e. their tasks queue is full: queue size \>= maximum queue size).
276 */
277 readonly emitter?: EventEmitterAsyncResource
278 /**
279 * Executes the specified function in the worker constructor with the task data input parameter.
280 *
281 * @param data - The optional task input data for the specified task function. This can only be structured-cloneable data.
282 * @param name - The optional name of the task function to execute. If not specified, the default task function will be executed.
283 * @param transferList - An optional array of transferable objects to transfer ownership of. Ownership of the transferred objects is given to the chosen pool's worker_threads worker and they should not be used in the main thread afterwards.
284 * @returns Promise that will be fulfilled when the task is completed.
285 */
286 readonly execute: (
287 data?: Data,
288 name?: string,
289 transferList?: readonly TransferListItem[]
290 ) => Promise<Response>
291 /**
292 * Starts the minimum number of workers in this pool.
293 */
294 readonly start: () => void
295 /**
296 * Terminates all workers in this pool.
297 */
298 readonly destroy: () => Promise<void>
299 /**
300 * Whether the specified task function exists in this pool.
301 *
302 * @param name - The name of the task function.
303 * @returns `true` if the task function exists, `false` otherwise.
304 */
305 readonly hasTaskFunction: (name: string) => boolean
306 /**
307 * Adds a task function to this pool.
308 * If a task function with the same name already exists, it will be overwritten.
309 *
310 * @param name - The name of the task function.
311 * @param fn - The task function.
312 * @returns `true` if the task function was added, `false` otherwise.
313 * @throws {@link https://nodejs.org/api/errors.html#class-typeerror} If the `name` parameter is not a string or an empty string.
314 * @throws {@link https://nodejs.org/api/errors.html#class-typeerror} If the `fn` parameter is not a function or task function object.
315 */
316 readonly addTaskFunction: (
317 name: string,
318 fn: TaskFunction<Data, Response> | TaskFunctionObject<Data, Response>
319 ) => Promise<boolean>
320 /**
321 * Removes a task function from this pool.
322 *
323 * @param name - The name of the task function.
324 * @returns `true` if the task function was removed, `false` otherwise.
325 */
326 readonly removeTaskFunction: (name: string) => Promise<boolean>
327 /**
328 * Lists the properties of task functions available in this pool.
329 *
330 * @returns The properties of task functions available in this pool.
331 */
332 readonly listTaskFunctionsProperties: () => TaskFunctionProperties[]
333 /**
334 * Sets the default task function in this pool.
335 *
336 * @param name - The name of the task function.
337 * @returns `true` if the default task function was set, `false` otherwise.
338 */
339 readonly setDefaultTaskFunction: (name: string) => Promise<boolean>
340 /**
341 * Sets the default worker choice strategy in this pool.
342 *
343 * @param workerChoiceStrategy - The default worker choice strategy.
344 * @param workerChoiceStrategyOptions - The worker choice strategy options.
345 */
346 readonly setWorkerChoiceStrategy: (
347 workerChoiceStrategy: WorkerChoiceStrategy,
348 workerChoiceStrategyOptions?: WorkerChoiceStrategyOptions
349 ) => void
350 /**
351 * Sets the worker choice strategy options in this pool.
352 *
353 * @param workerChoiceStrategyOptions - The worker choice strategy options.
354 * @returns `true` if the worker choice strategy options were set, `false` otherwise.
355 */
356 readonly setWorkerChoiceStrategyOptions: (
357 workerChoiceStrategyOptions: WorkerChoiceStrategyOptions
358 ) => boolean
359 /**
360 * Enables/disables the worker node tasks queue in this pool.
361 *
362 * @param enable - Whether to enable or disable the worker node tasks queue.
363 * @param tasksQueueOptions - The worker node tasks queue options.
364 */
365 readonly enableTasksQueue: (
366 enable: boolean,
367 tasksQueueOptions?: TasksQueueOptions
368 ) => void
369 /**
370 * Sets the worker node tasks queue options in this pool.
371 *
372 * @param tasksQueueOptions - The worker node tasks queue options.
373 */
374 readonly setTasksQueueOptions: (tasksQueueOptions: TasksQueueOptions) => void
375 }