refactor: encapsulate worker node handling logic into its own class
[poolifier.git] / src / pools / worker.ts
1 import type { CircularArray } from '../circular-array'
2
3 /**
4 * Callback invoked if the worker has received a message.
5 */
6 export type MessageHandler<Worker extends IWorker> = (
7 this: Worker,
8 message: unknown
9 ) => void
10
11 /**
12 * Callback invoked if the worker raised an error.
13 */
14 export type ErrorHandler<Worker extends IWorker> = (
15 this: Worker,
16 error: Error
17 ) => void
18
19 /**
20 * Callback invoked when the worker has started successfully.
21 */
22 export type OnlineHandler<Worker extends IWorker> = (this: Worker) => void
23
24 /**
25 * Callback invoked when the worker exits successfully.
26 */
27 export type ExitHandler<Worker extends IWorker> = (
28 this: Worker,
29 exitCode: number
30 ) => void
31
32 /**
33 * Message object that is passed as a task between main worker and worker.
34 *
35 * @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
36 * @internal
37 */
38 export interface Task<Data = unknown> {
39 /**
40 * Task name.
41 */
42 readonly name?: string
43 /**
44 * Task input data that will be passed to the worker.
45 */
46 readonly data?: Data
47 /**
48 * Timestamp.
49 */
50 readonly timestamp?: number
51 /**
52 * Message UUID.
53 */
54 readonly id?: string
55 }
56
57 /**
58 * Measurement statistics.
59 *
60 * @internal
61 */
62 export interface MeasurementStatistics {
63 /**
64 * Measurement aggregate.
65 */
66 aggregate?: number
67 /**
68 * Measurement minimum.
69 */
70 minimum?: number
71 /**
72 * Measurement maximum.
73 */
74 maximum?: number
75 /**
76 * Measurement average.
77 */
78 average?: number
79 /**
80 * Measurement median.
81 */
82 median?: number
83 /**
84 * Measurement history.
85 */
86 readonly history: CircularArray<number>
87 }
88
89 /**
90 * Event loop utilization measurement statistics.
91 *
92 * @internal
93 */
94 export interface EventLoopUtilizationMeasurementStatistics {
95 readonly idle: MeasurementStatistics
96 readonly active: MeasurementStatistics
97 utilization?: number
98 }
99
100 /**
101 * Task statistics.
102 *
103 * @internal
104 */
105 export interface TaskStatistics {
106 /**
107 * Number of executed tasks.
108 */
109 executed: number
110 /**
111 * Number of executing tasks.
112 */
113 executing: number
114 /**
115 * Number of queued tasks.
116 */
117 readonly queued: number
118 /**
119 * Maximum number of queued tasks.
120 */
121 readonly maxQueued: number
122 /**
123 * Number of failed tasks.
124 */
125 failed: number
126 }
127
128 /**
129 * Enumeration of worker types.
130 */
131 export const WorkerTypes = Object.freeze({
132 cluster: 'cluster',
133 thread: 'thread'
134 } as const)
135
136 /**
137 * Worker type.
138 */
139 export type WorkerType = keyof typeof WorkerTypes
140
141 /**
142 * Worker information.
143 *
144 * @internal
145 */
146 export interface WorkerInfo {
147 /**
148 * Worker id.
149 */
150 readonly id: number | undefined
151 /**
152 * Worker type.
153 */
154 type: WorkerType
155 /**
156 * Dynamic flag.
157 */
158 dynamic: boolean
159 /**
160 * Started flag.
161 */
162 started: boolean
163 }
164
165 /**
166 * Worker usage statistics.
167 *
168 * @internal
169 */
170 export interface WorkerUsage {
171 /**
172 * Tasks statistics.
173 */
174 readonly tasks: TaskStatistics
175 /**
176 * Tasks runtime statistics.
177 */
178 readonly runTime: MeasurementStatistics
179 /**
180 * Tasks wait time statistics.
181 */
182 readonly waitTime: MeasurementStatistics
183 /**
184 * Tasks event loop utilization statistics.
185 */
186 readonly elu: EventLoopUtilizationMeasurementStatistics
187 }
188
189 /**
190 * Worker interface.
191 */
192 export interface IWorker {
193 /**
194 * Worker id.
195 */
196 readonly id?: number
197 readonly threadId?: number
198 /**
199 * Registers an event listener.
200 *
201 * @param event - The event.
202 * @param handler - The event handler.
203 */
204 readonly on: ((event: 'message', handler: MessageHandler<this>) => void) &
205 ((event: 'error', handler: ErrorHandler<this>) => void) &
206 ((event: 'online', handler: OnlineHandler<this>) => void) &
207 ((event: 'exit', handler: ExitHandler<this>) => void)
208 /**
209 * Registers a listener to the exit event that will only be performed once.
210 *
211 * @param event - `'exit'`.
212 * @param handler - The exit handler.
213 */
214 readonly once: (event: 'exit', handler: ExitHandler<this>) => void
215 }
216
217 /**
218 * Worker node interface.
219 *
220 * @typeParam Worker - Type of worker.
221 * @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
222 * @internal
223 */
224 export interface IWorkerNode<Worker extends IWorker, Data = unknown> {
225 /**
226 * Worker node worker.
227 */
228 readonly worker: Worker
229 /**
230 * Worker node worker info.
231 */
232 readonly info: WorkerInfo
233 /**
234 * Worker node worker usage statistics.
235 */
236 usage: WorkerUsage
237 /**
238 * Worker node tasks queue size.
239 *
240 * @returns The tasks queue size.
241 */
242 readonly tasksQueueSize: () => number
243 /**
244 * Worker node enqueue task.
245 *
246 * @param task - The task to queue.
247 * @returns The task queue size.
248 */
249 readonly enqueueTask: (task: Task<Data>) => number
250 /**
251 * Worker node dequeue task.
252 *
253 * @returns The dequeued task.
254 */
255 readonly dequeueTask: () => Task<Data> | undefined
256 /**
257 * Worker node clear tasks queue.
258 */
259 readonly clearTasksQueue: () => void
260 /**
261 * Worker node reset usage statistics .
262 */
263 readonly resetUsage: () => void
264 }