Commit | Line | Data |
---|---|---|
c97c7edb | 1 | import type { Worker } from 'cluster' |
4f7fa42a | 2 | import type { JSONValue } from '../../utility-types' |
c97c7edb | 3 | import type { ClusterPoolOptions } from './fixed' |
325f50bc | 4 | import { FixedClusterPool } from './fixed' |
f045358d | 5 | |
4ade5f1f | 6 | /** |
729c563d | 7 | * A cluster pool with a dynamic number of workers, but a guaranteed minimum number of workers. |
4ade5f1f | 8 | * |
729c563d S |
9 | * This cluster pool creates new workers when the others are busy, up to the maximum number of workers. |
10 | * When the maximum number of workers is reached, an event is emitted. If you want to listen to this event, use the pool's `emitter`. | |
11 | * | |
12 | * @template Data Type of data sent to the worker. | |
13 | * @template Response Type of response of execution. | |
4ade5f1f | 14 | * |
325f50bc S |
15 | * @author [Christopher Quadflieg](https://github.com/Shinigami92) |
16 | * @since 2.0.0 | |
4ade5f1f | 17 | */ |
325f50bc | 18 | export class DynamicClusterPool< |
d3c8a1a8 S |
19 | Data extends JSONValue = JSONValue, |
20 | Response extends JSONValue = JSONValue | |
325f50bc | 21 | > extends FixedClusterPool<Data, Response> { |
4ade5f1f | 22 | /** |
729c563d S |
23 | * Constructs a new poolifier dynamic cluster pool. |
24 | * | |
25 | * @param min Minimum number of workers which are always active. | |
26 | * @param max Maximum number of workers that can be created by this pool. | |
27 | * @param filename Path to an implementation of a `ClusterWorker` file, which can be relative or absolute. | |
28 | * @param opts Options for this fixed cluster pool. Default: `{ maxTasks: 1000 }` | |
4ade5f1f S |
29 | */ |
30 | public constructor ( | |
c97c7edb | 31 | min: number, |
4ade5f1f | 32 | public readonly max: number, |
c97c7edb S |
33 | filename: string, |
34 | opts: ClusterPoolOptions = { maxTasks: 1000 } | |
4ade5f1f S |
35 | ) { |
36 | super(min, filename, opts) | |
4ade5f1f S |
37 | } |
38 | ||
729c563d S |
39 | /** |
40 | * Choose a worker for the next task. | |
41 | * | |
42 | * It will first check for and return an idle worker. | |
43 | * If all workers are busy, then it will try to create a new one up to the `max` worker count. | |
44 | * If the max worker count is reached, the emitter will emit a `FullPool` event and it will fall back to using a round robin algorithm to distribute the load. | |
50eceb07 S |
45 | * |
46 | * @returns Cluster worker. | |
729c563d | 47 | */ |
c97c7edb | 48 | protected chooseWorker (): Worker { |
4f7fa42a S |
49 | for (const [worker, numberOfTasks] of this.tasks) { |
50 | if (numberOfTasks === 0) { | |
51 | // A worker is free, use it | |
52 | return worker | |
4ade5f1f S |
53 | } |
54 | } | |
55 | ||
4f7fa42a S |
56 | if (this.workers.length === this.max) { |
57 | this.emitter.emit('FullPool') | |
58 | return super.chooseWorker() | |
4ade5f1f | 59 | } |
4f7fa42a S |
60 | |
61 | // All workers are busy, create a new worker | |
62 | const worker = this.createAndSetupWorker() | |
63 | this.registerWorkerMessageListener<Data>(worker, message => { | |
64 | if (message.kill) { | |
65 | this.sendToWorker(worker, { kill: 1 }) | |
66 | void this.destroyWorker(worker) | |
67 | } | |
68 | }) | |
69 | return worker | |
4ade5f1f S |
70 | } |
71 | } |