poolifier 2.2.0 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +190 -155
- package/lib/index.js +1 -1
- package/package.json +27 -23
package/lib/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
+
import EventEmitter from "events";
|
|
2
3
|
import { Worker } from "cluster";
|
|
4
|
+
import { Worker as ClusterWorker } from "cluster";
|
|
3
5
|
import { MessagePort, MessageChannel } from "worker_threads";
|
|
4
6
|
import { Worker as Worker$0 } from "worker_threads";
|
|
5
|
-
import EventEmitter from "events";
|
|
6
7
|
import { AsyncResource } from "async_hooks";
|
|
7
8
|
/**
|
|
8
9
|
* Enumeration of kill behaviors.
|
|
@@ -59,7 +60,7 @@ type Draft<T> = {
|
|
|
59
60
|
/**
|
|
60
61
|
* Message object that is passed between worker and main worker.
|
|
61
62
|
*/
|
|
62
|
-
interface MessageValue<Data = unknown, MainWorker extends
|
|
63
|
+
interface MessageValue<Data = unknown, MainWorker extends ClusterWorker | MessagePort | unknown = unknown> {
|
|
63
64
|
/**
|
|
64
65
|
* Input data that will be passed to the worker.
|
|
65
66
|
*/
|
|
@@ -79,7 +80,7 @@ interface MessageValue<Data = unknown, MainWorker extends Worker | MessagePort |
|
|
|
79
80
|
/**
|
|
80
81
|
* Reference to main worker.
|
|
81
82
|
*
|
|
82
|
-
*
|
|
83
|
+
* Only for internal use.
|
|
83
84
|
*/
|
|
84
85
|
readonly parent?: MainWorker;
|
|
85
86
|
}
|
|
@@ -89,7 +90,7 @@ interface MessageValue<Data = unknown, MainWorker extends Worker | MessagePort |
|
|
|
89
90
|
* @template Worker Type of worker.
|
|
90
91
|
* @template Response Type of response of execution. This can only be serializable data.
|
|
91
92
|
*/
|
|
92
|
-
interface PromiseWorkerResponseWrapper<Worker extends
|
|
93
|
+
interface PromiseWorkerResponseWrapper<Worker extends AbstractPoolWorker, Response = unknown> {
|
|
93
94
|
/**
|
|
94
95
|
* Resolve callback to fulfill the promise.
|
|
95
96
|
*/
|
|
@@ -103,6 +104,81 @@ interface PromiseWorkerResponseWrapper<Worker extends IWorker, Response = unknow
|
|
|
103
104
|
*/
|
|
104
105
|
readonly worker: Worker;
|
|
105
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Callback invoked if the worker has received a message.
|
|
109
|
+
*/
|
|
110
|
+
type MessageHandler<Worker> = (this: Worker, m: unknown) => void;
|
|
111
|
+
/**
|
|
112
|
+
* Callback invoked if the worker raised an error.
|
|
113
|
+
*/
|
|
114
|
+
type ErrorHandler<Worker> = (this: Worker, e: Error) => void;
|
|
115
|
+
/**
|
|
116
|
+
* Callback invoked when the worker has started successfully.
|
|
117
|
+
*/
|
|
118
|
+
type OnlineHandler<Worker> = (this: Worker) => void;
|
|
119
|
+
/**
|
|
120
|
+
* Callback invoked when the worker exits successfully.
|
|
121
|
+
*/
|
|
122
|
+
type ExitHandler<Worker> = (this: Worker, code: number) => void;
|
|
123
|
+
/**
|
|
124
|
+
* Basic interface that describes the minimum required implementation of listener events for a pool worker.
|
|
125
|
+
*/
|
|
126
|
+
interface IPoolWorker {
|
|
127
|
+
/**
|
|
128
|
+
* Worker identifier.
|
|
129
|
+
*/
|
|
130
|
+
readonly id?: number;
|
|
131
|
+
/**
|
|
132
|
+
* Register a listener to the message event.
|
|
133
|
+
*
|
|
134
|
+
* @param event `'message'`.
|
|
135
|
+
* @param handler The message handler.
|
|
136
|
+
*/
|
|
137
|
+
on(event: "message", handler: MessageHandler<this>): void;
|
|
138
|
+
/**
|
|
139
|
+
* Register a listener to the error event.
|
|
140
|
+
*
|
|
141
|
+
* @param event `'error'`.
|
|
142
|
+
* @param handler The error handler.
|
|
143
|
+
*/
|
|
144
|
+
on(event: "error", handler: ErrorHandler<this>): void;
|
|
145
|
+
/**
|
|
146
|
+
* Register a listener to the online event.
|
|
147
|
+
*
|
|
148
|
+
* @param event `'online'`.
|
|
149
|
+
* @param handler The online handler.
|
|
150
|
+
*/
|
|
151
|
+
on(event: "online", handler: OnlineHandler<this>): void;
|
|
152
|
+
/**
|
|
153
|
+
* Register a listener to the exit event.
|
|
154
|
+
*
|
|
155
|
+
* @param event `'exit'`.
|
|
156
|
+
* @param handler The exit handler.
|
|
157
|
+
*/
|
|
158
|
+
on(event: "exit", handler: ExitHandler<this>): void;
|
|
159
|
+
/**
|
|
160
|
+
* Register a listener to the exit event that will only performed once.
|
|
161
|
+
*
|
|
162
|
+
* @param event `'exit'`.
|
|
163
|
+
* @param handler The exit handler.
|
|
164
|
+
*/
|
|
165
|
+
once(event: "exit", handler: ExitHandler<this>): void;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Basic class that implement the minimum required for a pool worker.
|
|
169
|
+
*/
|
|
170
|
+
declare abstract class AbstractPoolWorker implements IPoolWorker {
|
|
171
|
+
/** @inheritDoc */
|
|
172
|
+
abstract on(event: "message", handler: MessageHandler<this>): void;
|
|
173
|
+
/** @inheritDoc */
|
|
174
|
+
abstract on(event: "error", handler: ErrorHandler<this>): void;
|
|
175
|
+
/** @inheritDoc */
|
|
176
|
+
abstract on(event: "online", handler: OnlineHandler<this>): void;
|
|
177
|
+
/** @inheritDoc */
|
|
178
|
+
abstract on(event: "exit", handler: ExitHandler<this>): void;
|
|
179
|
+
/** @inheritDoc */
|
|
180
|
+
abstract once(event: "exit", handler: ExitHandler<this>): void;
|
|
181
|
+
}
|
|
106
182
|
/**
|
|
107
183
|
* Enumeration of worker choice strategies.
|
|
108
184
|
*/
|
|
@@ -115,44 +191,35 @@ declare const WorkerChoiceStrategies: Readonly<{
|
|
|
115
191
|
*/
|
|
116
192
|
type WorkerChoiceStrategy = keyof typeof WorkerChoiceStrategies;
|
|
117
193
|
/**
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
* @template Worker Type of worker.
|
|
121
|
-
* @template Data Type of data sent to the worker. This can only be serializable data.
|
|
122
|
-
* @template Response Type of response of execution. This can only be serializable data.
|
|
194
|
+
* Options for a poolifier pool.
|
|
123
195
|
*/
|
|
124
|
-
|
|
125
|
-
private readonly pool;
|
|
126
|
-
private createDynamicallyWorkerCallback;
|
|
127
|
-
// Will be set by setter in constructor
|
|
128
|
-
private workerChoiceStrategy;
|
|
196
|
+
interface PoolOptions<Worker> {
|
|
129
197
|
/**
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
* @param pool The pool instance.
|
|
133
|
-
* @param createDynamicallyWorkerCallback The worker creation callback for dynamic pool.
|
|
134
|
-
* @param workerChoiceStrategy The worker choice strategy.
|
|
198
|
+
* A function that will listen for message event on each worker.
|
|
135
199
|
*/
|
|
136
|
-
|
|
200
|
+
messageHandler?: MessageHandler<Worker>;
|
|
137
201
|
/**
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
* @param workerChoiceStrategy The worker choice strategy.
|
|
141
|
-
* @returns The worker choice strategy instance for the pool type.
|
|
202
|
+
* A function that will listen for error event on each worker.
|
|
142
203
|
*/
|
|
143
|
-
|
|
204
|
+
errorHandler?: ErrorHandler<Worker>;
|
|
144
205
|
/**
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
* @param workerChoiceStrategy The worker choice strategy to set.
|
|
206
|
+
* A function that will listen for online event on each worker.
|
|
148
207
|
*/
|
|
149
|
-
|
|
208
|
+
onlineHandler?: OnlineHandler<Worker>;
|
|
150
209
|
/**
|
|
151
|
-
*
|
|
210
|
+
* A function that will listen for exit event on each worker.
|
|
211
|
+
*/
|
|
212
|
+
exitHandler?: ExitHandler<Worker>;
|
|
213
|
+
/**
|
|
214
|
+
* The work choice strategy to use in this pool.
|
|
215
|
+
*/
|
|
216
|
+
workerChoiceStrategy?: WorkerChoiceStrategy;
|
|
217
|
+
/**
|
|
218
|
+
* Pool events emission.
|
|
152
219
|
*
|
|
153
|
-
* @
|
|
220
|
+
* @default true
|
|
154
221
|
*/
|
|
155
|
-
|
|
222
|
+
enableEvents?: boolean;
|
|
156
223
|
}
|
|
157
224
|
/**
|
|
158
225
|
* Contract definition for a poolifier pool.
|
|
@@ -198,7 +265,7 @@ declare class PoolEmitter extends EventEmitter {
|
|
|
198
265
|
* @template Data Type of data sent to the worker.
|
|
199
266
|
* @template Response Type of response of execution.
|
|
200
267
|
*/
|
|
201
|
-
interface IPoolInternal<Worker extends
|
|
268
|
+
interface IPoolInternal<Worker extends AbstractPoolWorker, Data = unknown, Response = unknown> extends IPool<Data, Response> {
|
|
202
269
|
/**
|
|
203
270
|
* List of currently available workers.
|
|
204
271
|
*/
|
|
@@ -239,105 +306,68 @@ interface IPoolInternal<Worker extends IWorker, Data = unknown, Response = unkno
|
|
|
239
306
|
*/
|
|
240
307
|
readonly numberOfRunningTasks: number;
|
|
241
308
|
/**
|
|
242
|
-
* Find a
|
|
309
|
+
* Find a free worker based on the number of tasks the worker has applied.
|
|
243
310
|
*
|
|
244
|
-
* If
|
|
311
|
+
* If a worker is found with `0` running tasks, it is detected as free and returned.
|
|
245
312
|
*
|
|
246
|
-
* If no
|
|
313
|
+
* If no free worker is found, `false` is returned.
|
|
247
314
|
*
|
|
248
|
-
* @returns A
|
|
315
|
+
* @returns A free worker if there is one, otherwise `false`.
|
|
249
316
|
*/
|
|
250
|
-
|
|
251
|
-
Worker,
|
|
252
|
-
number
|
|
253
|
-
] | false;
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* Callback invoked if the worker has received a message.
|
|
257
|
-
*/
|
|
258
|
-
type MessageHandler<Worker> = (this: Worker, m: unknown) => void;
|
|
259
|
-
/**
|
|
260
|
-
* Callback invoked if the worker raised an error.
|
|
261
|
-
*/
|
|
262
|
-
type ErrorHandler<Worker> = (this: Worker, e: Error) => void;
|
|
263
|
-
/**
|
|
264
|
-
* Callback invoked when the worker has started successfully.
|
|
265
|
-
*/
|
|
266
|
-
type OnlineHandler<Worker> = (this: Worker) => void;
|
|
267
|
-
/**
|
|
268
|
-
* Callback invoked when the worker exits successfully.
|
|
269
|
-
*/
|
|
270
|
-
type ExitHandler<Worker> = (this: Worker, code: number) => void;
|
|
271
|
-
/**
|
|
272
|
-
* Basic interface that describes the minimum required implementation of listener events for a pool-worker.
|
|
273
|
-
*/
|
|
274
|
-
interface IWorker {
|
|
317
|
+
findFreeWorker(): Worker | false;
|
|
275
318
|
/**
|
|
276
|
-
*
|
|
319
|
+
* Get worker index.
|
|
277
320
|
*
|
|
278
|
-
* @param
|
|
279
|
-
* @
|
|
321
|
+
* @param worker The worker.
|
|
322
|
+
* @returns The worker index.
|
|
280
323
|
*/
|
|
281
|
-
|
|
324
|
+
getWorkerIndex(worker: Worker): number;
|
|
282
325
|
/**
|
|
283
|
-
*
|
|
326
|
+
* Get worker running tasks.
|
|
284
327
|
*
|
|
285
|
-
* @param
|
|
286
|
-
* @
|
|
287
|
-
*/
|
|
288
|
-
on(event: "error", handler: ErrorHandler<this>): void;
|
|
289
|
-
/**
|
|
290
|
-
* Register a listener to the online event.
|
|
291
|
-
*
|
|
292
|
-
* @param event `'online'`.
|
|
293
|
-
* @param handler The online handler.
|
|
294
|
-
*/
|
|
295
|
-
on(event: "online", handler: OnlineHandler<this>): void;
|
|
296
|
-
/**
|
|
297
|
-
* Register a listener to the exit event.
|
|
298
|
-
*
|
|
299
|
-
* @param event `'exit'`.
|
|
300
|
-
* @param handler The exit handler.
|
|
301
|
-
*/
|
|
302
|
-
on(event: "exit", handler: ExitHandler<this>): void;
|
|
303
|
-
/**
|
|
304
|
-
* Register a listener to the exit event that will only performed once.
|
|
305
|
-
*
|
|
306
|
-
* @param event `'exit'`.
|
|
307
|
-
* @param handler The exit handler.
|
|
328
|
+
* @param worker The worker.
|
|
329
|
+
* @returns The number of tasks currently running on the worker.
|
|
308
330
|
*/
|
|
309
|
-
|
|
331
|
+
getWorkerRunningTasks(worker: Worker): number | undefined;
|
|
310
332
|
}
|
|
311
333
|
/**
|
|
312
|
-
*
|
|
334
|
+
* The worker choice strategy context.
|
|
335
|
+
*
|
|
336
|
+
* @template Worker Type of worker.
|
|
337
|
+
* @template Data Type of data sent to the worker. This can only be serializable data.
|
|
338
|
+
* @template Response Type of response of execution. This can only be serializable data.
|
|
313
339
|
*/
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
messageHandler?: MessageHandler<Worker>;
|
|
319
|
-
/**
|
|
320
|
-
* A function that will listen for error event on each worker.
|
|
321
|
-
*/
|
|
322
|
-
errorHandler?: ErrorHandler<Worker>;
|
|
340
|
+
declare class WorkerChoiceStrategyContext<Worker extends AbstractPoolWorker, Data, Response> {
|
|
341
|
+
private readonly pool;
|
|
342
|
+
private createDynamicallyWorkerCallback;
|
|
343
|
+
private workerChoiceStrategy;
|
|
323
344
|
/**
|
|
324
|
-
*
|
|
345
|
+
* Worker choice strategy context constructor.
|
|
346
|
+
*
|
|
347
|
+
* @param pool The pool instance.
|
|
348
|
+
* @param createDynamicallyWorkerCallback The worker creation callback for dynamic pool.
|
|
349
|
+
* @param workerChoiceStrategy The worker choice strategy.
|
|
325
350
|
*/
|
|
326
|
-
|
|
351
|
+
constructor(pool: IPoolInternal<Worker, Data, Response>, createDynamicallyWorkerCallback: () => Worker, workerChoiceStrategy?: WorkerChoiceStrategy);
|
|
327
352
|
/**
|
|
328
|
-
*
|
|
353
|
+
* Get the worker choice strategy instance specific to the pool type.
|
|
354
|
+
*
|
|
355
|
+
* @param workerChoiceStrategy The worker choice strategy.
|
|
356
|
+
* @returns The worker choice strategy instance for the pool type.
|
|
329
357
|
*/
|
|
330
|
-
|
|
358
|
+
private getPoolWorkerChoiceStrategy;
|
|
331
359
|
/**
|
|
332
|
-
*
|
|
360
|
+
* Set the worker choice strategy to use in the context.
|
|
361
|
+
*
|
|
362
|
+
* @param workerChoiceStrategy The worker choice strategy to set.
|
|
333
363
|
*/
|
|
334
|
-
workerChoiceStrategy
|
|
364
|
+
setWorkerChoiceStrategy(workerChoiceStrategy: WorkerChoiceStrategy): void;
|
|
335
365
|
/**
|
|
336
|
-
*
|
|
366
|
+
* Choose a worker with the underlying selection strategy.
|
|
337
367
|
*
|
|
338
|
-
* @
|
|
368
|
+
* @returns The chosen one.
|
|
339
369
|
*/
|
|
340
|
-
|
|
370
|
+
execute(): Worker;
|
|
341
371
|
}
|
|
342
372
|
/**
|
|
343
373
|
* Base class containing some shared logic for all poolifier pools.
|
|
@@ -346,17 +376,17 @@ interface PoolOptions<Worker> {
|
|
|
346
376
|
* @template Data Type of data sent to the worker. This can only be serializable data.
|
|
347
377
|
* @template Response Type of response of execution. This can only be serializable data.
|
|
348
378
|
*/
|
|
349
|
-
declare abstract class AbstractPool<Worker extends
|
|
379
|
+
declare abstract class AbstractPool<Worker extends AbstractPoolWorker, Data = unknown, Response = unknown> implements IPoolInternal<Worker, Data, Response> {
|
|
350
380
|
readonly numberOfWorkers: number;
|
|
351
381
|
readonly filePath: string;
|
|
352
382
|
readonly opts: PoolOptions<Worker>;
|
|
353
|
-
/** @
|
|
383
|
+
/** @inheritDoc */
|
|
354
384
|
readonly workers: Worker[];
|
|
355
|
-
/** @
|
|
385
|
+
/** @inheritDoc */
|
|
356
386
|
readonly tasks: Map<Worker, number>;
|
|
357
|
-
/** @
|
|
387
|
+
/** @inheritDoc */
|
|
358
388
|
readonly emitter?: PoolEmitter;
|
|
359
|
-
/** @
|
|
389
|
+
/** @inheritDoc */
|
|
360
390
|
readonly max?: number;
|
|
361
391
|
/**
|
|
362
392
|
* The promise map.
|
|
@@ -388,23 +418,24 @@ declare abstract class AbstractPool<Worker extends IWorker, Data = unknown, Resp
|
|
|
388
418
|
private checkFilePath;
|
|
389
419
|
private checkNumberOfWorkers;
|
|
390
420
|
private checkPoolOptions;
|
|
391
|
-
/** @
|
|
421
|
+
/** @inheritDoc */
|
|
392
422
|
abstract get type(): PoolType;
|
|
393
|
-
/** @
|
|
423
|
+
/** @inheritDoc */
|
|
394
424
|
get numberOfRunningTasks(): number;
|
|
395
|
-
/** @
|
|
425
|
+
/** @inheritDoc */
|
|
426
|
+
getWorkerRunningTasks(worker: Worker): number | undefined;
|
|
427
|
+
/** @inheritDoc */
|
|
428
|
+
getWorkerIndex(worker: Worker): number;
|
|
429
|
+
/** @inheritDoc */
|
|
396
430
|
setWorkerChoiceStrategy(workerChoiceStrategy: WorkerChoiceStrategy): void;
|
|
397
|
-
/** @
|
|
431
|
+
/** @inheritDoc */
|
|
398
432
|
abstract get busy(): boolean;
|
|
399
433
|
protected internalGetBusyStatus(): boolean;
|
|
400
|
-
/** @
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
number
|
|
404
|
-
] | false;
|
|
405
|
-
/** @inheritdoc */
|
|
434
|
+
/** @inheritDoc */
|
|
435
|
+
findFreeWorker(): Worker | false;
|
|
436
|
+
/** @inheritDoc */
|
|
406
437
|
execute(data: Data): Promise<Response>;
|
|
407
|
-
/** @
|
|
438
|
+
/** @inheritDoc */
|
|
408
439
|
destroy(): Promise<void>;
|
|
409
440
|
/**
|
|
410
441
|
* Shut down given worker.
|
|
@@ -490,7 +521,7 @@ declare abstract class AbstractPool<Worker extends IWorker, Data = unknown, Resp
|
|
|
490
521
|
/**
|
|
491
522
|
* This function is the listener registered for each worker.
|
|
492
523
|
*
|
|
493
|
-
* @returns The listener function to execute when a message is
|
|
524
|
+
* @returns The listener function to execute when a message is received from a worker.
|
|
494
525
|
*/
|
|
495
526
|
protected workerListener(): (message: MessageValue<Response>) => void;
|
|
496
527
|
private checkAndEmitBusy;
|
|
@@ -529,23 +560,23 @@ declare class FixedClusterPool<Data = unknown, Response = unknown> extends Abstr
|
|
|
529
560
|
* @param [opts={}] Options for this fixed cluster pool.
|
|
530
561
|
*/
|
|
531
562
|
constructor(numberOfWorkers: number, filePath: string, opts?: ClusterPoolOptions);
|
|
532
|
-
/** @
|
|
563
|
+
/** @inheritDoc */
|
|
533
564
|
protected setupHook(): void;
|
|
534
|
-
/** @
|
|
565
|
+
/** @inheritDoc */
|
|
535
566
|
protected isMain(): boolean;
|
|
536
|
-
/** @
|
|
567
|
+
/** @inheritDoc */
|
|
537
568
|
destroyWorker(worker: Worker): void;
|
|
538
|
-
/** @
|
|
569
|
+
/** @inheritDoc */
|
|
539
570
|
protected sendToWorker(worker: Worker, message: MessageValue<Data>): void;
|
|
540
|
-
/** @
|
|
571
|
+
/** @inheritDoc */
|
|
541
572
|
registerWorkerMessageListener<Message extends Data | Response>(worker: Worker, listener: (message: MessageValue<Message>) => void): void;
|
|
542
|
-
/** @
|
|
573
|
+
/** @inheritDoc */
|
|
543
574
|
protected createWorker(): Worker;
|
|
544
|
-
/** @
|
|
575
|
+
/** @inheritDoc */
|
|
545
576
|
protected afterWorkerSetup(worker: Worker): void;
|
|
546
|
-
/** @
|
|
577
|
+
/** @inheritDoc */
|
|
547
578
|
get type(): PoolType;
|
|
548
|
-
/** @
|
|
579
|
+
/** @inheritDoc */
|
|
549
580
|
get busy(): boolean;
|
|
550
581
|
}
|
|
551
582
|
/**
|
|
@@ -570,9 +601,9 @@ declare class DynamicClusterPool<Data = unknown, Response = unknown> extends Fix
|
|
|
570
601
|
* @param [opts={}] Options for this dynamic cluster pool.
|
|
571
602
|
*/
|
|
572
603
|
constructor(min: number, max: number, filePath: string, opts?: ClusterPoolOptions);
|
|
573
|
-
/** @
|
|
604
|
+
/** @inheritDoc */
|
|
574
605
|
get type(): PoolType;
|
|
575
|
-
/** @
|
|
606
|
+
/** @inheritDoc */
|
|
576
607
|
get busy(): boolean;
|
|
577
608
|
}
|
|
578
609
|
/**
|
|
@@ -600,21 +631,21 @@ declare class FixedThreadPool<Data = unknown, Response = unknown> extends Abstra
|
|
|
600
631
|
* @param [opts={}] Options for this fixed thread pool.
|
|
601
632
|
*/
|
|
602
633
|
constructor(numberOfThreads: number, filePath: string, opts?: PoolOptions<ThreadWorkerWithMessageChannel>);
|
|
603
|
-
/** @
|
|
634
|
+
/** @inheritDoc */
|
|
604
635
|
protected isMain(): boolean;
|
|
605
|
-
/** @
|
|
636
|
+
/** @inheritDoc */
|
|
606
637
|
destroyWorker(worker: ThreadWorkerWithMessageChannel): Promise<void>;
|
|
607
|
-
/** @
|
|
638
|
+
/** @inheritDoc */
|
|
608
639
|
protected sendToWorker(worker: ThreadWorkerWithMessageChannel, message: MessageValue<Data>): void;
|
|
609
|
-
/** @
|
|
640
|
+
/** @inheritDoc */
|
|
610
641
|
registerWorkerMessageListener<Message extends Data | Response>(messageChannel: ThreadWorkerWithMessageChannel, listener: (message: MessageValue<Message>) => void): void;
|
|
611
|
-
/** @
|
|
642
|
+
/** @inheritDoc */
|
|
612
643
|
protected createWorker(): ThreadWorkerWithMessageChannel;
|
|
613
|
-
/** @
|
|
644
|
+
/** @inheritDoc */
|
|
614
645
|
protected afterWorkerSetup(worker: ThreadWorkerWithMessageChannel): void;
|
|
615
|
-
/** @
|
|
646
|
+
/** @inheritDoc */
|
|
616
647
|
get type(): PoolType;
|
|
617
|
-
/** @
|
|
648
|
+
/** @inheritDoc */
|
|
618
649
|
get busy(): boolean;
|
|
619
650
|
}
|
|
620
651
|
/**
|
|
@@ -639,9 +670,9 @@ declare class DynamicThreadPool<Data = unknown, Response = unknown> extends Fixe
|
|
|
639
670
|
* @param [opts={}] Options for this dynamic thread pool.
|
|
640
671
|
*/
|
|
641
672
|
constructor(min: number, max: number, filePath: string, opts?: PoolOptions<ThreadWorkerWithMessageChannel>);
|
|
642
|
-
/** @
|
|
673
|
+
/** @inheritDoc */
|
|
643
674
|
get type(): PoolType;
|
|
644
|
-
/** @
|
|
675
|
+
/** @inheritDoc */
|
|
645
676
|
get busy(): boolean;
|
|
646
677
|
}
|
|
647
678
|
/**
|
|
@@ -653,7 +684,6 @@ declare class DynamicThreadPool<Data = unknown, Response = unknown> extends Fixe
|
|
|
653
684
|
*/
|
|
654
685
|
declare abstract class AbstractWorker<MainWorker extends Worker | MessagePort, Data = unknown, Response = unknown> extends AsyncResource {
|
|
655
686
|
protected mainWorker: MainWorker | undefined | null;
|
|
656
|
-
readonly opts: WorkerOptions;
|
|
657
687
|
/**
|
|
658
688
|
* Timestamp of the last task processed by this worker.
|
|
659
689
|
*/
|
|
@@ -662,6 +692,10 @@ declare abstract class AbstractWorker<MainWorker extends Worker | MessagePort, D
|
|
|
662
692
|
* Handler Id of the `aliveInterval` worker alive check.
|
|
663
693
|
*/
|
|
664
694
|
protected readonly aliveInterval?: NodeJS.Timeout;
|
|
695
|
+
/**
|
|
696
|
+
* Options for the worker.
|
|
697
|
+
*/
|
|
698
|
+
readonly opts: WorkerOptions;
|
|
665
699
|
/**
|
|
666
700
|
* Constructs a new poolifier worker.
|
|
667
701
|
*
|
|
@@ -672,6 +706,7 @@ declare abstract class AbstractWorker<MainWorker extends Worker | MessagePort, D
|
|
|
672
706
|
* @param opts Options for the worker.
|
|
673
707
|
*/
|
|
674
708
|
constructor(type: string, isMain: boolean, fn: (data: Data) => Response, mainWorker: MainWorker | undefined | null, opts?: WorkerOptions);
|
|
709
|
+
protected messageListener(value: MessageValue<Data, MainWorker>, fn: (data: Data) => Response): void;
|
|
675
710
|
private checkWorkerOptions;
|
|
676
711
|
/**
|
|
677
712
|
* Check if the `fn` parameter is passed to the constructor.
|
|
@@ -731,7 +766,7 @@ declare abstract class AbstractWorker<MainWorker extends Worker | MessagePort, D
|
|
|
731
766
|
* @author [Christopher Quadflieg](https://github.com/Shinigami92)
|
|
732
767
|
* @since 2.0.0
|
|
733
768
|
*/
|
|
734
|
-
declare class ClusterWorker<Data = unknown, Response = unknown> extends AbstractWorker<Worker, Data, Response> {
|
|
769
|
+
declare class ClusterWorker$0<Data = unknown, Response = unknown> extends AbstractWorker<Worker, Data, Response> {
|
|
735
770
|
/**
|
|
736
771
|
* Constructs a new poolifier cluster worker.
|
|
737
772
|
*
|
|
@@ -739,9 +774,9 @@ declare class ClusterWorker<Data = unknown, Response = unknown> extends Abstract
|
|
|
739
774
|
* @param opts Options for the worker.
|
|
740
775
|
*/
|
|
741
776
|
constructor(fn: (data: Data) => Response, opts?: WorkerOptions);
|
|
742
|
-
/** @
|
|
777
|
+
/** @inheritDoc */
|
|
743
778
|
protected sendToMainWorker(message: MessageValue<Response>): void;
|
|
744
|
-
/** @
|
|
779
|
+
/** @inheritDoc */
|
|
745
780
|
protected handleError(e: Error | string): string;
|
|
746
781
|
}
|
|
747
782
|
/**
|
|
@@ -766,8 +801,8 @@ declare class ThreadWorker<Data = unknown, Response = unknown> extends AbstractW
|
|
|
766
801
|
* @param opts Options for the worker.
|
|
767
802
|
*/
|
|
768
803
|
constructor(fn: (data: Data) => Response, opts?: WorkerOptions);
|
|
769
|
-
/** @
|
|
804
|
+
/** @inheritDoc */
|
|
770
805
|
protected sendToMainWorker(message: MessageValue<Response>): void;
|
|
771
806
|
}
|
|
772
|
-
export
|
|
773
|
-
export {
|
|
807
|
+
export { DynamicClusterPool, FixedClusterPool, WorkerChoiceStrategies, DynamicThreadPool, FixedThreadPool, AbstractWorker, ClusterWorker$0 as ClusterWorker, ThreadWorker, KillBehaviors };
|
|
808
|
+
export type { ClusterPoolOptions, IPool, PoolOptions, ErrorHandler, ExitHandler, IPoolWorker, OnlineHandler, WorkerChoiceStrategy, ThreadWorkerWithMessageChannel, KillBehavior, WorkerOptions };
|
package/lib/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("events"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("events"),r=require("cluster"),t=require("worker_threads"),s=require("async_hooks");function o(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var i,n=o(e),a=o(r);!function(e){e.FIXED="fixed",e.DYNAMIC="dynamic"}(i||(i={}));class h extends n.default{}const c=()=>{},l=Object.freeze({SOFT:"SOFT",HARD:"HARD"});const k=Object.freeze({ROUND_ROBIN:"ROUND_ROBIN",LESS_RECENTLY_USED:"LESS_RECENTLY_USED"});class u{constructor(e){this.pool=e,this.isDynamicPool=this.pool.type===i.DYNAMIC}}class p extends u{choose(){let e,r=1/0;for(const t of this.pool.workers){const s=this.pool.getWorkerRunningTasks(t);if(!1===this.isDynamicPool&&0===s)return t;s<r&&(e=t,r=s)}return e}}class d extends u{constructor(){super(...arguments),this.nextWorkerIndex=0}choose(){const e=this.pool.workers[this.nextWorkerIndex];return this.nextWorkerIndex=this.nextWorkerIndex===this.pool.workers.length-1?0:this.nextWorkerIndex+1,e}}class W{static getWorkerChoiceStrategy(e,r=k.ROUND_ROBIN){switch(r){case k.ROUND_ROBIN:return new d(e);case k.LESS_RECENTLY_USED:return new p(e);default:throw new Error(`Worker choice strategy '${r}' not found`)}}}class g extends u{constructor(e,r,t=k.ROUND_ROBIN){super(e),this.createDynamicallyWorkerCallback=r,this.workerChoiceStrategy=W.getWorkerChoiceStrategy(this.pool,t)}choose(){const e=this.pool.findFreeWorker();return e||(this.pool.busy?this.workerChoiceStrategy.choose():this.createDynamicallyWorkerCallback())}}class m{constructor(e,r,t=k.ROUND_ROBIN){this.pool=e,this.createDynamicallyWorkerCallback=r,this.setWorkerChoiceStrategy(t)}getPoolWorkerChoiceStrategy(e=k.ROUND_ROBIN){return this.pool.type===i.DYNAMIC?new g(this.pool,this.createDynamicallyWorkerCallback,e):W.getWorkerChoiceStrategy(this.pool,e)}setWorkerChoiceStrategy(e){this.workerChoiceStrategy=this.getPoolWorkerChoiceStrategy(e)}execute(){return this.workerChoiceStrategy.choose()}}class y{constructor(e,r,t){if(this.numberOfWorkers=e,this.filePath=r,this.opts=t,this.workers=[],this.tasks=new Map,this.promiseMap=new Map,this.nextMessageId=0,!this.isMain())throw new Error("Cannot start a pool from a worker!");this.checkNumberOfWorkers(this.numberOfWorkers),this.checkFilePath(this.filePath),this.checkPoolOptions(this.opts),this.setupHook();for(let e=1;e<=this.numberOfWorkers;e++)this.createAndSetupWorker();this.opts.enableEvents&&(this.emitter=new h),this.workerChoiceStrategyContext=new m(this,(()=>{const e=this.createAndSetupWorker();return this.registerWorkerMessageListener(e,(r=>{var t;t=l.HARD,(r.kill===t||0===this.getWorkerRunningTasks(e))&&this.destroyWorker(e)})),e}),this.opts.workerChoiceStrategy)}checkFilePath(e){if(!e)throw new Error("Please specify a file with a worker implementation")}checkNumberOfWorkers(e){if(null==e)throw new Error("Cannot instantiate a pool without specifying the number of workers");if(!Number.isSafeInteger(e))throw new Error("Cannot instantiate a pool with a non integer number of workers");if(e<0)throw new Error("Cannot instantiate a pool with a negative number of workers");if(this.type===i.FIXED&&0===e)throw new Error("Cannot instantiate a fixed pool with no worker")}checkPoolOptions(e){var r,t;this.opts.workerChoiceStrategy=null!==(r=e.workerChoiceStrategy)&&void 0!==r?r:k.ROUND_ROBIN,this.opts.enableEvents=null===(t=e.enableEvents)||void 0===t||t}get numberOfRunningTasks(){return this.promiseMap.size}getWorkerRunningTasks(e){return this.tasks.get(e)}getWorkerIndex(e){return this.workers.indexOf(e)}setWorkerChoiceStrategy(e){this.opts.workerChoiceStrategy=e,this.workerChoiceStrategyContext.setWorkerChoiceStrategy(e)}internalGetBusyStatus(){return this.numberOfRunningTasks>=this.numberOfWorkers&&!1===this.findFreeWorker()}findFreeWorker(){for(const e of this.workers)if(0===this.getWorkerRunningTasks(e))return e;return!1}execute(e){const r=this.chooseWorker(),t=++this.nextMessageId,s=this.internalExecute(r,t);return this.checkAndEmitBusy(),e=null!=e?e:{},this.sendToWorker(r,{data:e,id:t}),s}async destroy(){await Promise.all(this.workers.map((e=>this.destroyWorker(e))))}setupHook(){}increaseWorkersTask(e){this.stepWorkerNumberOfTasks(e,1)}decreaseWorkersTasks(e){this.stepWorkerNumberOfTasks(e,-1)}stepWorkerNumberOfTasks(e,r){const t=this.tasks.get(e);if(void 0===t)throw Error("Worker could not be found in tasks map");this.tasks.set(e,t+r)}removeWorker(e){this.workers.splice(this.getWorkerIndex(e),1),this.tasks.delete(e)}chooseWorker(){return this.workerChoiceStrategyContext.execute()}internalExecute(e,r){return this.increaseWorkersTask(e),new Promise(((t,s)=>{this.promiseMap.set(r,{resolve:t,reject:s,worker:e})}))}createAndSetupWorker(){var e,r,t,s;const o=this.createWorker();return o.on("message",null!==(e=this.opts.messageHandler)&&void 0!==e?e:c),o.on("error",null!==(r=this.opts.errorHandler)&&void 0!==r?r:c),o.on("online",null!==(t=this.opts.onlineHandler)&&void 0!==t?t:c),o.on("exit",null!==(s=this.opts.exitHandler)&&void 0!==s?s:c),o.once("exit",(()=>this.removeWorker(o))),this.workers.push(o),this.tasks.set(o,0),this.afterWorkerSetup(o),o}workerListener(){return e=>{if(void 0!==e.id){const r=this.promiseMap.get(e.id);void 0!==r&&(this.decreaseWorkersTasks(r.worker),e.error?r.reject(e.error):r.resolve(e.data),this.promiseMap.delete(e.id))}}}checkAndEmitBusy(){var e;this.opts.enableEvents&&this.busy&&(null===(e=this.emitter)||void 0===e||e.emit("busy"))}}class w extends y{constructor(e,r,t={}){super(e,r,t),this.opts=t}setupHook(){a.default.setupPrimary({exec:this.filePath})}isMain(){return a.default.isPrimary}destroyWorker(e){this.sendToWorker(e,{kill:1}),e.kill()}sendToWorker(e,r){e.send(r)}registerWorkerMessageListener(e,r){e.on("message",r)}createWorker(){return a.default.fork(this.opts.env)}afterWorkerSetup(e){this.registerWorkerMessageListener(e,super.workerListener())}get type(){return i.FIXED}get busy(){return this.internalGetBusyStatus()}}class f extends y{constructor(e,r,t={}){super(e,r,t)}isMain(){return t.isMainThread}async destroyWorker(e){this.sendToWorker(e,{kill:1}),await e.terminate()}sendToWorker(e,r){e.postMessage(r)}registerWorkerMessageListener(e,r){var t;null===(t=e.port2)||void 0===t||t.on("message",r)}createWorker(){return new t.Worker(this.filePath,{env:t.SHARE_ENV})}afterWorkerSetup(e){const{port1:r,port2:s}=new t.MessageChannel;e.postMessage({parent:r},[r]),e.port1=r,e.port2=s,this.registerWorkerMessageListener(e,super.workerListener())}get type(){return i.FIXED}get busy(){return this.internalGetBusyStatus()}}const v=l.SOFT;class x extends s.AsyncResource{constructor(e,r,t,s,o={killBehavior:v,maxInactiveTime:6e4}){var i,n;super(e),this.mainWorker=s,this.opts=o,this.checkFunctionInput(t),this.checkWorkerOptions(this.opts),this.lastTaskTimestamp=Date.now(),r||(this.aliveInterval=setInterval(this.checkAlive.bind(this),(null!==(i=this.opts.maxInactiveTime)&&void 0!==i?i:6e4)/2),this.checkAlive.bind(this)()),null===(n=this.mainWorker)||void 0===n||n.on("message",(e=>{this.messageListener(e,t)}))}messageListener(e,r){void 0!==e.data&&void 0!==e.id?this.opts.async?this.runInAsyncScope(this.runAsync.bind(this),this,r,e):this.runInAsyncScope(this.run.bind(this),this,r,e):void 0!==e.parent?this.mainWorker=e.parent:void 0!==e.kill&&(this.aliveInterval&&clearInterval(this.aliveInterval),this.emitDestroy())}checkWorkerOptions(e){var r,t;this.opts.killBehavior=null!==(r=e.killBehavior)&&void 0!==r?r:v,this.opts.maxInactiveTime=null!==(t=e.maxInactiveTime)&&void 0!==t?t:6e4,this.opts.async=!!e.async}checkFunctionInput(e){if(!e)throw new Error("fn parameter is mandatory")}getMainWorker(){if(!this.mainWorker)throw new Error("Main worker was not set");return this.mainWorker}checkAlive(){var e;Date.now()-this.lastTaskTimestamp>(null!==(e=this.opts.maxInactiveTime)&&void 0!==e?e:6e4)&&this.sendToMainWorker({kill:this.opts.killBehavior})}handleError(e){return e}run(e,r){try{const t=e(r.data);this.sendToMainWorker({data:t,id:r.id})}catch(e){const t=this.handleError(e);this.sendToMainWorker({error:t,id:r.id})}finally{this.lastTaskTimestamp=Date.now()}}runAsync(e,r){e(r.data).then((e=>(this.sendToMainWorker({data:e,id:r.id}),null))).catch((e=>{const t=this.handleError(e);this.sendToMainWorker({error:t,id:r.id})})).finally((()=>{this.lastTaskTimestamp=Date.now()})).catch(c)}}exports.AbstractWorker=x,exports.ClusterWorker=class extends x{constructor(e,r={}){super("worker-cluster-pool:poolifier",a.default.isPrimary,e,a.default.worker,r)}sendToMainWorker(e){this.getMainWorker().send(e)}handleError(e){return e instanceof Error?e.message:e}},exports.DynamicClusterPool=class extends w{constructor(e,r,t,s={}){super(e,t,s),this.max=r}get type(){return i.DYNAMIC}get busy(){return this.workers.length===this.max}},exports.DynamicThreadPool=class extends f{constructor(e,r,t,s={}){super(e,t,s),this.max=r}get type(){return i.DYNAMIC}get busy(){return this.workers.length===this.max}},exports.FixedClusterPool=w,exports.FixedThreadPool=f,exports.KillBehaviors=l,exports.ThreadWorker=class extends x{constructor(e,r={}){super("worker-thread-pool:poolifier",t.isMainThread,e,t.parentPort,r)}sendToMainWorker(e){this.getMainWorker().postMessage(e)}},exports.WorkerChoiceStrategies=k;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "poolifier",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "A fast, easy to use Node.js Worker Thread Pool and Cluster Pool implementation",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -16,9 +16,10 @@
|
|
|
16
16
|
"coverage": "nyc report --reporter=lcov",
|
|
17
17
|
"coverage:html": "nyc report --reporter=html",
|
|
18
18
|
"format": "prettier --loglevel silent --write .; prettierx --write .",
|
|
19
|
-
"lint": "eslint .",
|
|
20
|
-
"lint:fix": "eslint . --fix",
|
|
19
|
+
"lint": "eslint . --cache",
|
|
20
|
+
"lint:fix": "eslint . --cache --fix",
|
|
21
21
|
"typedoc": "typedoc",
|
|
22
|
+
"sonar:properties": "./updateSonarProps.sh",
|
|
22
23
|
"prepublishOnly": "npm run build:prod"
|
|
23
24
|
},
|
|
24
25
|
"repository": {
|
|
@@ -62,37 +63,40 @@
|
|
|
62
63
|
"lib"
|
|
63
64
|
],
|
|
64
65
|
"devDependencies": {
|
|
65
|
-
"@types/node": "^
|
|
66
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
67
|
-
"@typescript-eslint/parser": "^5.
|
|
66
|
+
"@types/node": "^18.8.3",
|
|
67
|
+
"@typescript-eslint/eslint-plugin": "^5.39.0",
|
|
68
|
+
"@typescript-eslint/parser": "^5.39.0",
|
|
68
69
|
"benchmark": "^2.1.4",
|
|
69
|
-
"eslint": "^8.
|
|
70
|
-
"eslint-config-standard": "^
|
|
71
|
-
"eslint-define-config": "^1.
|
|
72
|
-
"eslint-
|
|
73
|
-
"eslint-plugin-
|
|
70
|
+
"eslint": "^8.25.0",
|
|
71
|
+
"eslint-config-standard": "^17.0.0",
|
|
72
|
+
"eslint-define-config": "^1.7.0",
|
|
73
|
+
"eslint-import-resolver-typescript": "^3.5.1",
|
|
74
|
+
"eslint-plugin-import": "^2.26.0",
|
|
75
|
+
"eslint-plugin-jsdoc": "^39.3.6",
|
|
76
|
+
"eslint-plugin-n": "^15.3.0",
|
|
74
77
|
"eslint-plugin-node": "^11.1.0",
|
|
75
78
|
"eslint-plugin-prettierx": "^0.18.0",
|
|
76
|
-
"eslint-plugin-promise": "^6.0.
|
|
77
|
-
"eslint-plugin-spellcheck": "0.0.19",
|
|
78
|
-
"expect": "^
|
|
79
|
-
"microtime": "^3.
|
|
80
|
-
"mocha": "^
|
|
81
|
-
"mochawesome": "^7.
|
|
79
|
+
"eslint-plugin-promise": "^6.0.1",
|
|
80
|
+
"eslint-plugin-spellcheck": "^0.0.19",
|
|
81
|
+
"expect": "^29.1.2",
|
|
82
|
+
"microtime": "^3.1.1",
|
|
83
|
+
"mocha": "^10.0.0",
|
|
84
|
+
"mochawesome": "^7.1.3",
|
|
82
85
|
"nyc": "^15.1.0",
|
|
83
|
-
"prettier": "^2.
|
|
84
|
-
"prettier-plugin-organize-imports": "^
|
|
86
|
+
"prettier": "^2.7.1",
|
|
87
|
+
"prettier-plugin-organize-imports": "^3.1.1",
|
|
85
88
|
"prettierx": "^0.18.3",
|
|
86
|
-
"rollup": "^2.
|
|
89
|
+
"rollup": "^2.79.1",
|
|
87
90
|
"rollup-plugin-analyzer": "^4.0.0",
|
|
88
91
|
"rollup-plugin-command": "^1.1.3",
|
|
89
92
|
"rollup-plugin-delete": "^2.0.0",
|
|
90
93
|
"rollup-plugin-istanbul": "^3.0.0",
|
|
91
94
|
"rollup-plugin-terser": "^7.0.2",
|
|
92
|
-
"rollup-plugin-ts": "^
|
|
95
|
+
"rollup-plugin-ts": "^3.0.2",
|
|
96
|
+
"sinon": "^14.0.1",
|
|
93
97
|
"source-map-support": "^0.5.21",
|
|
94
|
-
"typedoc": "^0.
|
|
95
|
-
"typescript": "^4.
|
|
98
|
+
"typedoc": "^0.23.15",
|
|
99
|
+
"typescript": "^4.8.4"
|
|
96
100
|
},
|
|
97
101
|
"engines": {
|
|
98
102
|
"node": ">=16.0.0",
|