perf: avoid branching on pool type
[poolifier.git] / src / pools / cluster / fixed.ts
1 import cluster, { type Worker } from 'node:cluster'
2 import type { MessageValue } from '../../utility-types'
3 import { AbstractPool } from '../abstract-pool'
4 import { type PoolOptions, type PoolType, PoolTypes } from '../pool'
5 import { type WorkerType, WorkerTypes } from '../worker'
6
7 /**
8 * Options for a poolifier cluster pool.
9 */
10 export type ClusterPoolOptions = PoolOptions<Worker>
11
12 /**
13 * A cluster pool with a fixed number of workers.
14 *
15 * @typeParam Data - Type of data sent to the worker. This can only be structured-cloneable data.
16 * @typeParam Response - Type of execution response. This can only be structured-cloneable data.
17 * @author [Christopher Quadflieg](https://github.com/Shinigami92)
18 * @since 2.0.0
19 */
20 export class FixedClusterPool<
21 Data = unknown,
22 Response = unknown
23 > extends AbstractPool<Worker, Data, Response> {
24 /**
25 * Constructs a new poolifier fixed cluster pool.
26 *
27 * @param numberOfWorkers - Number of workers for this pool.
28 * @param filePath - Path to an implementation of a `ClusterWorker` file, which can be relative or absolute.
29 * @param opts - Options for this fixed cluster pool.
30 */
31 public constructor (
32 numberOfWorkers: number,
33 filePath: string,
34 opts: ClusterPoolOptions = {},
35 maximumNumberOfWorkers?: number
36 ) {
37 super(numberOfWorkers, filePath, opts, maximumNumberOfWorkers)
38 }
39
40 /** @inheritDoc */
41 protected setupHook (): void {
42 cluster.setupPrimary({ ...this.opts.settings, exec: this.filePath })
43 }
44
45 /** @inheritDoc */
46 protected isMain (): boolean {
47 return cluster.isPrimary
48 }
49
50 /** @inheritDoc */
51 protected sendToWorker (
52 workerNodeKey: number,
53 message: MessageValue<Data>
54 ): void {
55 this.workerNodes[workerNodeKey].worker.send({
56 ...message,
57 workerId: this.getWorkerInfo(workerNodeKey).id as number
58 })
59 }
60
61 /** @inheritDoc */
62 protected sendStartupMessageToWorker (workerNodeKey: number): void {
63 this.sendToWorker(workerNodeKey, {
64 ready: false
65 })
66 }
67
68 /** @inheritDoc */
69 protected registerWorkerMessageListener<Message extends Data | Response>(
70 workerNodeKey: number,
71 listener: (message: MessageValue<Message>) => void
72 ): void {
73 this.workerNodes[workerNodeKey].worker.on('message', listener)
74 }
75
76 /** @inheritDoc */
77 protected registerOnceWorkerMessageListener<Message extends Data | Response>(
78 workerNodeKey: number,
79 listener: (message: MessageValue<Message>) => void
80 ): void {
81 this.workerNodes[workerNodeKey].worker.once('message', listener)
82 }
83
84 /** @inheritDoc */
85 protected deregisterWorkerMessageListener<Message extends Data | Response>(
86 workerNodeKey: number,
87 listener: (message: MessageValue<Message>) => void
88 ): void {
89 this.workerNodes[workerNodeKey].worker.off('message', listener)
90 }
91
92 /** @inheritDoc */
93 protected shallCreateDynamicWorker (): boolean {
94 return false
95 }
96
97 /** @inheritDoc */
98 protected checkAndEmitDynamicWorkerCreationEvents (): void {}
99
100 /** @inheritDoc */
101 protected get type (): PoolType {
102 return PoolTypes.fixed
103 }
104
105 /** @inheritDoc */
106 protected get worker (): WorkerType {
107 return WorkerTypes.cluster
108 }
109
110 /** @inheritDoc */
111 protected get busy (): boolean {
112 return this.internalBusy()
113 }
114 }