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