@nsshunt/stsmessaging 1.0.78 → 1.0.79
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/README.IPCMessageHandler.md +624 -0
- package/README.IPCMessageHandlerPair.md +702 -0
- package/README.IPCMessageHandlerPairManager.md +1289 -0
- package/README.IPCMessageHandlerPairManagerGenNotes.md +420 -0
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/types/ipcMessageHandler.d.ts +1 -1
- package/types/ipcMessageHandlerPair.d.ts +2 -1
- package/types/ipcMessageHandlerPair.d.ts.map +1 -1
- package/types/ipcMessageHandlerPairManager.d.ts +152 -0
- package/types/ipcMessageHandlerPairManager.d.ts.map +1 -0
- package/types/ipcMessageHandlerPairManager.test.d.ts +3 -0
- package/types/ipcMessageHandlerPairManager.test.d.ts.map +1 -0
|
@@ -0,0 +1,1289 @@
|
|
|
1
|
+
# IPCMessageHandlerPairManager
|
|
2
|
+
|
|
3
|
+
`IPCMessageHandlerPairManager` manages a collection of `IPCMessageHandlerPair` instances on the **server / cluster primary** side.
|
|
4
|
+
|
|
5
|
+
Each worker gets its own dedicated `IPCMessageHandlerPair`.
|
|
6
|
+
|
|
7
|
+
The manager is responsible for:
|
|
8
|
+
|
|
9
|
+
- maintaining the worker collection;
|
|
10
|
+
- creating and removing worker pairs;
|
|
11
|
+
- sending messages to one worker;
|
|
12
|
+
- broadcasting messages to all workers;
|
|
13
|
+
- registering events across every pair;
|
|
14
|
+
- applying existing event registrations to workers added later;
|
|
15
|
+
- automatically cleaning up worker pairs when workers exit.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Architecture
|
|
20
|
+
|
|
21
|
+
The manager uses a **collection of one-to-one IPC pairs**.
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
IPCMessageHandlerPairManager
|
|
25
|
+
│
|
|
26
|
+
├── Worker 1 -> IPCMessageHandlerPair -> MessagingManager
|
|
27
|
+
├── Worker 2 -> IPCMessageHandlerPair -> MessagingManager
|
|
28
|
+
├── Worker 3 -> IPCMessageHandlerPair -> MessagingManager
|
|
29
|
+
└── Worker 4 -> IPCMessageHandlerPair -> MessagingManager
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Each `IPCMessageHandlerPair` is responsible for exactly one primary/worker IPC relationship.
|
|
33
|
+
|
|
34
|
+
The manager owns the collection.
|
|
35
|
+
|
|
36
|
+
This separates responsibilities cleanly:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
IPCMessageHandlerPairManager
|
|
40
|
+
-> worker collection
|
|
41
|
+
-> worker lifecycle
|
|
42
|
+
-> targeted messaging
|
|
43
|
+
-> broadcasting
|
|
44
|
+
-> event propagation
|
|
45
|
+
|
|
46
|
+
IPCMessageHandlerPair
|
|
47
|
+
-> one worker connection
|
|
48
|
+
-> IPC send/receive
|
|
49
|
+
-> event dispatch
|
|
50
|
+
-> request/response messaging
|
|
51
|
+
|
|
52
|
+
MessagingManager
|
|
53
|
+
-> message IDs
|
|
54
|
+
-> request/response correlation
|
|
55
|
+
-> timeouts
|
|
56
|
+
-> message protocol
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
# Why This Class Exists
|
|
62
|
+
|
|
63
|
+
Previously, `IPCMessageHandler` combined two separate responsibilities:
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
IPC connection handling
|
|
67
|
+
+
|
|
68
|
+
worker collection management
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`IPCMessageHandlerPairManager` separates those responsibilities.
|
|
72
|
+
|
|
73
|
+
Instead of:
|
|
74
|
+
|
|
75
|
+
```text
|
|
76
|
+
IPCMessageHandler
|
|
77
|
+
|
|
|
78
|
+
+-- Worker 1
|
|
79
|
+
+-- Worker 2
|
|
80
|
+
+-- Worker 3
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
the architecture becomes:
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
IPCMessageHandlerPairManager
|
|
87
|
+
|
|
|
88
|
+
+-- IPCMessageHandlerPair -> Worker 1
|
|
89
|
+
+-- IPCMessageHandlerPair -> Worker 2
|
|
90
|
+
+-- IPCMessageHandlerPair -> Worker 3
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
This allows the pair class to remain focused on a single IPC connection while the manager handles multi-worker behavior.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
# File
|
|
98
|
+
|
|
99
|
+
```text
|
|
100
|
+
ipcMessageHandlerPairManager.ts
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
# Constructor
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
new IPCMessageHandlerPairManager(options);
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Options
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
export interface IPCMessageHandlerPairManagerOptions {
|
|
115
|
+
logger: ISTSLogger;
|
|
116
|
+
requestResponseMessageTimeout: number;
|
|
117
|
+
namespace: string;
|
|
118
|
+
ignoreEvents?: string[];
|
|
119
|
+
autoRemoveOnWorkerExit?: boolean;
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## logger
|
|
126
|
+
|
|
127
|
+
Logger passed to every `IPCMessageHandlerPair`.
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
logger: ISTSLogger;
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## requestResponseMessageTimeout
|
|
136
|
+
|
|
137
|
+
Request/response timeout passed to each pair.
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
requestResponseMessageTimeout: 5000;
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Each pair creates its own `MessagingManager`, so each worker connection has its own in-flight request tracking and timeout handling.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## namespace
|
|
148
|
+
|
|
149
|
+
Messaging namespace shared by all pairs managed by this instance.
|
|
150
|
+
|
|
151
|
+
Example:
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
namespace: "STS_WORKERS";
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
All worker pairs can use the same namespace while their underlying `MessagingManager` instances maintain their own message identities.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## ignoreEvents
|
|
162
|
+
|
|
163
|
+
Optional event names whose errors should be ignored by the pair's `emit()` implementation.
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
ignoreEvents: ["optional-event"];
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## autoRemoveOnWorkerExit
|
|
172
|
+
|
|
173
|
+
Controls whether a pair is automatically removed when its cluster worker exits.
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
autoRemoveOnWorkerExit: true;
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
This is the default.
|
|
180
|
+
|
|
181
|
+
Disable automatic cleanup with:
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
autoRemoveOnWorkerExit: false;
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
This can be useful when another higher-level process manager already owns worker lifecycle cleanup.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
# Internal Collections
|
|
192
|
+
|
|
193
|
+
The manager maintains three important collections.
|
|
194
|
+
|
|
195
|
+
## Pair Collection
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
Map<number, IPCMessageHandlerPair>;
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The key is the Node.js cluster worker ID.
|
|
202
|
+
|
|
203
|
+
Conceptually:
|
|
204
|
+
|
|
205
|
+
```text
|
|
206
|
+
1 -> IPCMessageHandlerPair
|
|
207
|
+
2 -> IPCMessageHandlerPair
|
|
208
|
+
3 -> IPCMessageHandlerPair
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Worker Collection
|
|
214
|
+
|
|
215
|
+
The manager also retains the actual `Worker` references.
|
|
216
|
+
|
|
217
|
+
Conceptually:
|
|
218
|
+
|
|
219
|
+
```text
|
|
220
|
+
1 -> Worker
|
|
221
|
+
2 -> Worker
|
|
222
|
+
3 -> Worker
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
This allows worker lifecycle management to remain separate from the pair abstraction.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Event Collection
|
|
230
|
+
|
|
231
|
+
Manager-level event handlers are also retained.
|
|
232
|
+
|
|
233
|
+
Conceptually:
|
|
234
|
+
|
|
235
|
+
```text
|
|
236
|
+
"worker-ready" -> callback
|
|
237
|
+
"status" -> callback
|
|
238
|
+
"shutdown" -> callback
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
This is important because workers can be added after events have already been registered.
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
# size
|
|
246
|
+
|
|
247
|
+
Returns the number of workers currently managed.
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
manager.size;
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Example:
|
|
254
|
+
|
|
255
|
+
```ts
|
|
256
|
+
console.log(manager.size);
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
If three workers are registered:
|
|
260
|
+
|
|
261
|
+
```text
|
|
262
|
+
3
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
# pairs
|
|
268
|
+
|
|
269
|
+
Returns a read-only view of the current worker-to-pair map.
|
|
270
|
+
|
|
271
|
+
```ts
|
|
272
|
+
manager.pairs;
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Example:
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
for (const [workerId, pair] of manager.pairs) {
|
|
279
|
+
console.log(workerId, pair);
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
# workerIds
|
|
286
|
+
|
|
287
|
+
Returns all worker IDs currently managed.
|
|
288
|
+
|
|
289
|
+
```ts
|
|
290
|
+
manager.workerIds;
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Example:
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
const ids = manager.workerIds;
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Possible result:
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
[1, 2, 3];
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
# AddWorker()
|
|
308
|
+
|
|
309
|
+
Adds a cluster worker to the manager and creates its dedicated `IPCMessageHandlerPair`.
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
manager.AddWorker(worker);
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Example:
|
|
316
|
+
|
|
317
|
+
```ts
|
|
318
|
+
const worker = cluster.fork();
|
|
319
|
+
|
|
320
|
+
manager.AddWorker(worker);
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Internally the manager:
|
|
324
|
+
|
|
325
|
+
1. checks whether the worker is already registered;
|
|
326
|
+
2. creates a new `IPCMessageHandlerPair`;
|
|
327
|
+
3. configures the pair with `role: "SERVER"`;
|
|
328
|
+
4. copies all existing manager event registrations into the pair;
|
|
329
|
+
5. starts the pair with the worker;
|
|
330
|
+
6. stores the pair;
|
|
331
|
+
7. stores the worker;
|
|
332
|
+
8. optionally registers automatic worker-exit cleanup.
|
|
333
|
+
|
|
334
|
+
Conceptually:
|
|
335
|
+
|
|
336
|
+
```text
|
|
337
|
+
AddWorker(worker)
|
|
338
|
+
|
|
|
339
|
+
v
|
|
340
|
+
Create IPCMessageHandlerPair
|
|
341
|
+
|
|
|
342
|
+
v
|
|
343
|
+
Apply existing events
|
|
344
|
+
|
|
|
345
|
+
v
|
|
346
|
+
pair.Start(worker)
|
|
347
|
+
|
|
|
348
|
+
v
|
|
349
|
+
Store pair + worker
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## Existing Worker
|
|
355
|
+
|
|
356
|
+
If the same `Worker` instance is already registered, the existing pair is returned.
|
|
357
|
+
|
|
358
|
+
```ts
|
|
359
|
+
const pair1 = manager.AddWorker(worker);
|
|
360
|
+
const pair2 = manager.AddWorker(worker);
|
|
361
|
+
|
|
362
|
+
pair1 === pair2;
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
Result:
|
|
366
|
+
|
|
367
|
+
```text
|
|
368
|
+
true
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## Reused Worker ID
|
|
374
|
+
|
|
375
|
+
If a worker ID already exists but belongs to a different `Worker` instance, the old pair is removed before the new one is added.
|
|
376
|
+
|
|
377
|
+
This helps avoid stale worker/pair relationships.
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
# RemoveWorker()
|
|
382
|
+
|
|
383
|
+
Stops and removes a worker's pair.
|
|
384
|
+
|
|
385
|
+
The method accepts either:
|
|
386
|
+
|
|
387
|
+
```ts
|
|
388
|
+
manager.RemoveWorker(worker);
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
or:
|
|
392
|
+
|
|
393
|
+
```ts
|
|
394
|
+
manager.RemoveWorker(worker.id);
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
It returns:
|
|
398
|
+
|
|
399
|
+
```ts
|
|
400
|
+
boolean;
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
`true` means a worker/pair was removed.
|
|
404
|
+
|
|
405
|
+
`false` means no pair existed for that worker ID.
|
|
406
|
+
|
|
407
|
+
Internally it:
|
|
408
|
+
|
|
409
|
+
1. removes any automatic `"exit"` listener;
|
|
410
|
+
2. stops the pair;
|
|
411
|
+
3. removes the pair;
|
|
412
|
+
4. removes the worker reference.
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
# HasWorker()
|
|
417
|
+
|
|
418
|
+
Checks whether a worker is currently managed.
|
|
419
|
+
|
|
420
|
+
```ts
|
|
421
|
+
manager.HasWorker(workerId);
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
Example:
|
|
425
|
+
|
|
426
|
+
```ts
|
|
427
|
+
if (manager.HasWorker(worker.id)) {
|
|
428
|
+
console.log("Worker is registered");
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
---
|
|
433
|
+
|
|
434
|
+
# GetPair()
|
|
435
|
+
|
|
436
|
+
Returns the `IPCMessageHandlerPair` associated with a worker ID.
|
|
437
|
+
|
|
438
|
+
```ts
|
|
439
|
+
const pair = manager.GetPair(workerId);
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
Return type:
|
|
443
|
+
|
|
444
|
+
```ts
|
|
445
|
+
IPCMessageHandlerPair | undefined;
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
This is useful when direct access to a pair is required.
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
452
|
+
# GetWorker()
|
|
453
|
+
|
|
454
|
+
Returns the cluster `Worker` associated with a worker ID.
|
|
455
|
+
|
|
456
|
+
```ts
|
|
457
|
+
const worker = manager.GetWorker(workerId);
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
Return type:
|
|
461
|
+
|
|
462
|
+
```ts
|
|
463
|
+
Worker | undefined;
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
---
|
|
467
|
+
|
|
468
|
+
# Event Registration
|
|
469
|
+
|
|
470
|
+
The manager exposes:
|
|
471
|
+
|
|
472
|
+
```ts
|
|
473
|
+
on();
|
|
474
|
+
off();
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
These behave differently from calling `on()` directly on one pair because the registration applies across the entire pair collection.
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
# on()
|
|
482
|
+
|
|
483
|
+
Registers an incoming IPC event across all workers.
|
|
484
|
+
|
|
485
|
+
```ts
|
|
486
|
+
manager.on(event, callback);
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
Example:
|
|
490
|
+
|
|
491
|
+
```ts
|
|
492
|
+
manager.on("worker-ready", (data, callback) => {
|
|
493
|
+
console.log("Worker ready:", data);
|
|
494
|
+
|
|
495
|
+
callback({
|
|
496
|
+
status: "OK",
|
|
497
|
+
});
|
|
498
|
+
});
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
The handler is applied to:
|
|
502
|
+
|
|
503
|
+
```text
|
|
504
|
+
Pair 1
|
|
505
|
+
Pair 2
|
|
506
|
+
Pair 3
|
|
507
|
+
...
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
---
|
|
511
|
+
|
|
512
|
+
## Event Propagation to Future Workers
|
|
513
|
+
|
|
514
|
+
The manager also remembers event registrations.
|
|
515
|
+
|
|
516
|
+
For example:
|
|
517
|
+
|
|
518
|
+
```ts
|
|
519
|
+
manager.on("get-status", callback);
|
|
520
|
+
|
|
521
|
+
manager.AddWorker(worker1);
|
|
522
|
+
manager.AddWorker(worker2);
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
Both workers receive the event registration even though they were added after `on()` was called.
|
|
526
|
+
|
|
527
|
+
The reverse order also works:
|
|
528
|
+
|
|
529
|
+
```ts
|
|
530
|
+
manager.AddWorker(worker1);
|
|
531
|
+
manager.AddWorker(worker2);
|
|
532
|
+
|
|
533
|
+
manager.on("get-status", callback);
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
The event is immediately registered on both existing pairs.
|
|
537
|
+
|
|
538
|
+
Therefore these two sequences are equivalent:
|
|
539
|
+
|
|
540
|
+
```text
|
|
541
|
+
Register event
|
|
542
|
+
Add workers
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
and:
|
|
546
|
+
|
|
547
|
+
```text
|
|
548
|
+
Add workers
|
|
549
|
+
Register event
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
This is an important responsibility of the manager because every `IPCMessageHandlerPair` owns its own event map.
|
|
553
|
+
|
|
554
|
+
---
|
|
555
|
+
|
|
556
|
+
# off()
|
|
557
|
+
|
|
558
|
+
Removes an event from all current pairs.
|
|
559
|
+
|
|
560
|
+
```ts
|
|
561
|
+
manager.off("get-status");
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
The event is also removed from the manager's retained event collection, so workers added later will not receive it.
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
# Targeted Messaging
|
|
569
|
+
|
|
570
|
+
One of the main benefits of the pair-based architecture is that the manager can target an individual worker directly.
|
|
571
|
+
|
|
572
|
+
---
|
|
573
|
+
|
|
574
|
+
# SendMessageTo()
|
|
575
|
+
|
|
576
|
+
Sends a raw request/response payload to one worker.
|
|
577
|
+
|
|
578
|
+
```ts
|
|
579
|
+
const response = await manager.SendMessageTo(workerId, payload);
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
Example:
|
|
583
|
+
|
|
584
|
+
```ts
|
|
585
|
+
const response = await manager.SendMessageTo(worker.id, {
|
|
586
|
+
command: "status",
|
|
587
|
+
});
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
Conceptually:
|
|
591
|
+
|
|
592
|
+
```text
|
|
593
|
+
Manager
|
|
594
|
+
|
|
|
595
|
+
+------> Pair 2 ------> Worker 2
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
Only the selected worker receives the message.
|
|
599
|
+
|
|
600
|
+
---
|
|
601
|
+
|
|
602
|
+
# emitTo()
|
|
603
|
+
|
|
604
|
+
Sends an event to one worker and returns its response.
|
|
605
|
+
|
|
606
|
+
```ts
|
|
607
|
+
const response = await manager.emitTo(workerId, event, ...args);
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
Example:
|
|
611
|
+
|
|
612
|
+
```ts
|
|
613
|
+
const response = await manager.emitTo(worker.id, "get-status");
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
With arguments:
|
|
617
|
+
|
|
618
|
+
```ts
|
|
619
|
+
const response = await manager.emitTo(
|
|
620
|
+
worker.id,
|
|
621
|
+
"process-resource",
|
|
622
|
+
resourceId
|
|
623
|
+
);
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
Conceptually:
|
|
627
|
+
|
|
628
|
+
```text
|
|
629
|
+
Primary
|
|
630
|
+
|
|
|
631
|
+
v
|
|
632
|
+
Manager
|
|
633
|
+
|
|
|
634
|
+
v
|
|
635
|
+
Pair(workerId)
|
|
636
|
+
|
|
|
637
|
+
v
|
|
638
|
+
Worker
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
---
|
|
642
|
+
|
|
643
|
+
# emitNoResponseTo()
|
|
644
|
+
|
|
645
|
+
Sends a fire-and-forget event to one worker.
|
|
646
|
+
|
|
647
|
+
```ts
|
|
648
|
+
await manager.emitNoResponseTo(workerId, event, ...args);
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
Example:
|
|
652
|
+
|
|
653
|
+
```ts
|
|
654
|
+
await manager.emitNoResponseTo(worker.id, "refresh-config");
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
No response is expected.
|
|
658
|
+
|
|
659
|
+
---
|
|
660
|
+
|
|
661
|
+
# Broadcasting
|
|
662
|
+
|
|
663
|
+
The manager provides explicit broadcast operations.
|
|
664
|
+
|
|
665
|
+
This is intentionally different from `IPCMessageHandler`, where server-side `SendMessage()` implicitly meant "send to every worker."
|
|
666
|
+
|
|
667
|
+
With the pair manager the caller chooses explicitly between:
|
|
668
|
+
|
|
669
|
+
```text
|
|
670
|
+
Send to one worker
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
and:
|
|
674
|
+
|
|
675
|
+
```text
|
|
676
|
+
Send to all workers
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
---
|
|
680
|
+
|
|
681
|
+
# SendMessageToAll()
|
|
682
|
+
|
|
683
|
+
Sends a raw payload to all workers.
|
|
684
|
+
|
|
685
|
+
```ts
|
|
686
|
+
const responses = await manager.SendMessageToAll(payload);
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
Return type:
|
|
690
|
+
|
|
691
|
+
```ts
|
|
692
|
+
IPCMessageHandlerPairManagerResponse[]
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
Each result contains:
|
|
696
|
+
|
|
697
|
+
```ts
|
|
698
|
+
{
|
|
699
|
+
(workerId, response);
|
|
700
|
+
}
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
Example:
|
|
704
|
+
|
|
705
|
+
```ts
|
|
706
|
+
const responses = await manager.SendMessageToAll({
|
|
707
|
+
command: "status",
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
for (const result of responses) {
|
|
711
|
+
console.log(result.workerId, result.response);
|
|
712
|
+
}
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
---
|
|
716
|
+
|
|
717
|
+
## Promise.all() Behavior
|
|
718
|
+
|
|
719
|
+
`SendMessageToAll()` uses `Promise.all()` semantics.
|
|
720
|
+
|
|
721
|
+
Therefore if one worker rejects or times out:
|
|
722
|
+
|
|
723
|
+
```text
|
|
724
|
+
Worker 1 -> success
|
|
725
|
+
Worker 2 -> timeout
|
|
726
|
+
Worker 3 -> success
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
the entire broadcast Promise rejects.
|
|
730
|
+
|
|
731
|
+
Use `SendMessageToAllSettled()` when every worker result is required regardless of individual failures.
|
|
732
|
+
|
|
733
|
+
---
|
|
734
|
+
|
|
735
|
+
# SendMessageToAllSettled()
|
|
736
|
+
|
|
737
|
+
Broadcasts a raw payload without allowing one failed worker to reject the complete operation.
|
|
738
|
+
|
|
739
|
+
```ts
|
|
740
|
+
const responses = await manager.SendMessageToAllSettled(payload);
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
Each result contains:
|
|
744
|
+
|
|
745
|
+
```ts
|
|
746
|
+
{
|
|
747
|
+
workerId,
|
|
748
|
+
status,
|
|
749
|
+
response?,
|
|
750
|
+
error?
|
|
751
|
+
}
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
Possible result:
|
|
755
|
+
|
|
756
|
+
```ts
|
|
757
|
+
[
|
|
758
|
+
{
|
|
759
|
+
workerId: 1,
|
|
760
|
+
status: "fulfilled",
|
|
761
|
+
response: {
|
|
762
|
+
status: "OK",
|
|
763
|
+
},
|
|
764
|
+
},
|
|
765
|
+
{
|
|
766
|
+
workerId: 2,
|
|
767
|
+
status: "rejected",
|
|
768
|
+
error: ...
|
|
769
|
+
},
|
|
770
|
+
{
|
|
771
|
+
workerId: 3,
|
|
772
|
+
status: "fulfilled",
|
|
773
|
+
response: {
|
|
774
|
+
status: "OK",
|
|
775
|
+
},
|
|
776
|
+
},
|
|
777
|
+
]
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
This is generally safer for operational broadcasts where one failed worker should not hide successful responses from the others.
|
|
781
|
+
|
|
782
|
+
---
|
|
783
|
+
|
|
784
|
+
# emitToAll()
|
|
785
|
+
|
|
786
|
+
Broadcasts an event to all workers.
|
|
787
|
+
|
|
788
|
+
```ts
|
|
789
|
+
const responses = await manager.emitToAll(event, ...args);
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
Example:
|
|
793
|
+
|
|
794
|
+
```ts
|
|
795
|
+
const responses = await manager.emitToAll("get-status");
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
Conceptually:
|
|
799
|
+
|
|
800
|
+
```text
|
|
801
|
+
Pair 1 -> Worker 1
|
|
802
|
+
/
|
|
803
|
+
Manager ----------- Pair 2 -> Worker 2
|
|
804
|
+
\
|
|
805
|
+
Pair 3 -> Worker 3
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
Each response includes the associated worker ID.
|
|
809
|
+
|
|
810
|
+
---
|
|
811
|
+
|
|
812
|
+
# emitToAllSettled()
|
|
813
|
+
|
|
814
|
+
Broadcasts an event to all workers and returns the result of every worker independently.
|
|
815
|
+
|
|
816
|
+
```ts
|
|
817
|
+
const responses = await manager.emitToAllSettled("get-status");
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
Example:
|
|
821
|
+
|
|
822
|
+
```ts
|
|
823
|
+
for (const result of responses) {
|
|
824
|
+
if (result.status === "fulfilled") {
|
|
825
|
+
console.log(`Worker ${result.workerId}`, result.response);
|
|
826
|
+
} else {
|
|
827
|
+
console.error(`Worker ${result.workerId} failed`, result.error);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
```
|
|
831
|
+
|
|
832
|
+
This is useful for:
|
|
833
|
+
|
|
834
|
+
- health checks;
|
|
835
|
+
- worker status collection;
|
|
836
|
+
- cluster diagnostics;
|
|
837
|
+
- configuration refresh;
|
|
838
|
+
- coordinated operations across many workers.
|
|
839
|
+
|
|
840
|
+
---
|
|
841
|
+
|
|
842
|
+
# emitNoResponseToAll()
|
|
843
|
+
|
|
844
|
+
Broadcasts a fire-and-forget event to every worker.
|
|
845
|
+
|
|
846
|
+
```ts
|
|
847
|
+
await manager.emitNoResponseToAll(event, ...args);
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
Example:
|
|
851
|
+
|
|
852
|
+
```ts
|
|
853
|
+
await manager.emitNoResponseToAll("refresh-config");
|
|
854
|
+
```
|
|
855
|
+
|
|
856
|
+
Conceptually:
|
|
857
|
+
|
|
858
|
+
```text
|
|
859
|
+
Manager
|
|
860
|
+
|
|
|
861
|
+
+----> Worker 1
|
|
862
|
+
+----> Worker 2
|
|
863
|
+
+----> Worker 3
|
|
864
|
+
```
|
|
865
|
+
|
|
866
|
+
No worker response is expected.
|
|
867
|
+
|
|
868
|
+
---
|
|
869
|
+
|
|
870
|
+
# Automatic Worker Cleanup
|
|
871
|
+
|
|
872
|
+
By default:
|
|
873
|
+
|
|
874
|
+
```ts
|
|
875
|
+
autoRemoveOnWorkerExit !== false;
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
causes the manager to register:
|
|
879
|
+
|
|
880
|
+
```ts
|
|
881
|
+
worker.once("exit", ...)
|
|
882
|
+
```
|
|
883
|
+
|
|
884
|
+
When the worker exits, the manager automatically removes its pair.
|
|
885
|
+
|
|
886
|
+
Conceptually:
|
|
887
|
+
|
|
888
|
+
```text
|
|
889
|
+
Worker exits
|
|
890
|
+
|
|
|
891
|
+
v
|
|
892
|
+
RemoveWorker(workerId)
|
|
893
|
+
|
|
|
894
|
+
+-- remove exit listener
|
|
895
|
+
+-- pair.Stop()
|
|
896
|
+
+-- remove pair
|
|
897
|
+
+-- remove worker
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
This prevents dead worker references from remaining in the collection.
|
|
901
|
+
|
|
902
|
+
---
|
|
903
|
+
|
|
904
|
+
# Disabling Automatic Cleanup
|
|
905
|
+
|
|
906
|
+
If another process manager already owns worker cleanup:
|
|
907
|
+
|
|
908
|
+
```ts
|
|
909
|
+
const manager = new IPCMessageHandlerPairManager({
|
|
910
|
+
logger,
|
|
911
|
+
requestResponseMessageTimeout: 5000,
|
|
912
|
+
namespace: "STS_WORKERS",
|
|
913
|
+
autoRemoveOnWorkerExit: false,
|
|
914
|
+
});
|
|
915
|
+
```
|
|
916
|
+
|
|
917
|
+
The caller must then explicitly perform:
|
|
918
|
+
|
|
919
|
+
```ts
|
|
920
|
+
manager.RemoveWorker(worker.id);
|
|
921
|
+
```
|
|
922
|
+
|
|
923
|
+
---
|
|
924
|
+
|
|
925
|
+
# Stop()
|
|
926
|
+
|
|
927
|
+
Stops every managed pair and clears the active worker collection.
|
|
928
|
+
|
|
929
|
+
```ts
|
|
930
|
+
manager.Stop();
|
|
931
|
+
```
|
|
932
|
+
|
|
933
|
+
Conceptually:
|
|
934
|
+
|
|
935
|
+
```text
|
|
936
|
+
Before:
|
|
937
|
+
|
|
938
|
+
Manager
|
|
939
|
+
├── Pair 1 -> Worker 1
|
|
940
|
+
├── Pair 2 -> Worker 2
|
|
941
|
+
└── Pair 3 -> Worker 3
|
|
942
|
+
|
|
943
|
+
|
|
944
|
+
manager.Stop()
|
|
945
|
+
|
|
946
|
+
|
|
947
|
+
After:
|
|
948
|
+
|
|
949
|
+
Manager
|
|
950
|
+
```
|
|
951
|
+
|
|
952
|
+
Each pair is stopped before removal.
|
|
953
|
+
|
|
954
|
+
---
|
|
955
|
+
|
|
956
|
+
## Event Registrations Are Retained
|
|
957
|
+
|
|
958
|
+
`Stop()` intentionally does not clear manager-level event registrations.
|
|
959
|
+
|
|
960
|
+
For example:
|
|
961
|
+
|
|
962
|
+
```ts
|
|
963
|
+
manager.on("get-status", callback);
|
|
964
|
+
|
|
965
|
+
manager.Stop();
|
|
966
|
+
|
|
967
|
+
manager.AddWorker(newWorker);
|
|
968
|
+
```
|
|
969
|
+
|
|
970
|
+
`newWorker` still receives the `"get-status"` registration.
|
|
971
|
+
|
|
972
|
+
This allows a manager to be stopped and reused without rebuilding all of its event configuration.
|
|
973
|
+
|
|
974
|
+
---
|
|
975
|
+
|
|
976
|
+
# Typical Primary Process Usage
|
|
977
|
+
|
|
978
|
+
```ts
|
|
979
|
+
import cluster from "node:cluster";
|
|
980
|
+
|
|
981
|
+
import { IPCMessageHandlerPairManager } from "./ipcMessageHandlerPairManager.js";
|
|
982
|
+
|
|
983
|
+
const manager = new IPCMessageHandlerPairManager({
|
|
984
|
+
logger,
|
|
985
|
+
requestResponseMessageTimeout: 5000,
|
|
986
|
+
namespace: "STS_WORKERS",
|
|
987
|
+
});
|
|
988
|
+
|
|
989
|
+
manager.on("worker-ready", (data, callback) => {
|
|
990
|
+
console.log("Worker ready:", data);
|
|
991
|
+
|
|
992
|
+
callback({
|
|
993
|
+
status: "OK",
|
|
994
|
+
});
|
|
995
|
+
});
|
|
996
|
+
|
|
997
|
+
const worker1 = cluster.fork();
|
|
998
|
+
const worker2 = cluster.fork();
|
|
999
|
+
const worker3 = cluster.fork();
|
|
1000
|
+
|
|
1001
|
+
manager.AddWorker(worker1);
|
|
1002
|
+
manager.AddWorker(worker2);
|
|
1003
|
+
manager.AddWorker(worker3);
|
|
1004
|
+
```
|
|
1005
|
+
|
|
1006
|
+
Result:
|
|
1007
|
+
|
|
1008
|
+
```text
|
|
1009
|
+
manager
|
|
1010
|
+
│
|
|
1011
|
+
├── worker1 -> pair1
|
|
1012
|
+
├── worker2 -> pair2
|
|
1013
|
+
└── worker3 -> pair3
|
|
1014
|
+
```
|
|
1015
|
+
|
|
1016
|
+
---
|
|
1017
|
+
|
|
1018
|
+
# Send to One Worker
|
|
1019
|
+
|
|
1020
|
+
```ts
|
|
1021
|
+
const response = await manager.emitTo(worker2.id, "get-status");
|
|
1022
|
+
|
|
1023
|
+
console.log(response);
|
|
1024
|
+
```
|
|
1025
|
+
|
|
1026
|
+
Only `worker2` receives the event.
|
|
1027
|
+
|
|
1028
|
+
---
|
|
1029
|
+
|
|
1030
|
+
# Send to All Workers
|
|
1031
|
+
|
|
1032
|
+
```ts
|
|
1033
|
+
const responses = await manager.emitToAll("get-status");
|
|
1034
|
+
|
|
1035
|
+
console.log(responses);
|
|
1036
|
+
```
|
|
1037
|
+
|
|
1038
|
+
Every registered worker receives the event.
|
|
1039
|
+
|
|
1040
|
+
---
|
|
1041
|
+
|
|
1042
|
+
# Safe Broadcast
|
|
1043
|
+
|
|
1044
|
+
```ts
|
|
1045
|
+
const results = await manager.emitToAllSettled("get-status");
|
|
1046
|
+
|
|
1047
|
+
for (const result of results) {
|
|
1048
|
+
if (result.status === "fulfilled") {
|
|
1049
|
+
console.log(`Worker ${result.workerId} OK`, result.response);
|
|
1050
|
+
} else {
|
|
1051
|
+
console.log(`Worker ${result.workerId} FAILED`, result.error);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
```
|
|
1055
|
+
|
|
1056
|
+
---
|
|
1057
|
+
|
|
1058
|
+
# Worker-Side Usage
|
|
1059
|
+
|
|
1060
|
+
The worker does **not** use `IPCMessageHandlerPairManager`.
|
|
1061
|
+
|
|
1062
|
+
Each worker uses one `IPCMessageHandlerPair`.
|
|
1063
|
+
|
|
1064
|
+
```ts
|
|
1065
|
+
import { IPCMessageHandlerPair } from "./ipcMessageHandlerPair.js";
|
|
1066
|
+
|
|
1067
|
+
const ipc = new IPCMessageHandlerPair({
|
|
1068
|
+
logger,
|
|
1069
|
+
requestResponseMessageTimeout: 5000,
|
|
1070
|
+
namespace: "STS_WORKERS",
|
|
1071
|
+
role: "CLIENT",
|
|
1072
|
+
});
|
|
1073
|
+
|
|
1074
|
+
ipc.on("get-status", (callback) => {
|
|
1075
|
+
callback({
|
|
1076
|
+
pid: process.pid,
|
|
1077
|
+
status: "OK",
|
|
1078
|
+
});
|
|
1079
|
+
});
|
|
1080
|
+
|
|
1081
|
+
ipc.Start();
|
|
1082
|
+
```
|
|
1083
|
+
|
|
1084
|
+
Architecture:
|
|
1085
|
+
|
|
1086
|
+
```text
|
|
1087
|
+
PRIMARY
|
|
1088
|
+
|
|
1089
|
+
IPCMessageHandlerPairManager
|
|
1090
|
+
|
|
|
1091
|
+
+-- Pair 1
|
|
1092
|
+
+-- Pair 2
|
|
1093
|
+
+-- Pair 3
|
|
1094
|
+
|
|
1095
|
+
|
|
1096
|
+
WORKERS
|
|
1097
|
+
|
|
1098
|
+
Worker 1
|
|
1099
|
+
|
|
|
1100
|
+
+-- IPCMessageHandlerPair(CLIENT)
|
|
1101
|
+
|
|
1102
|
+
Worker 2
|
|
1103
|
+
|
|
|
1104
|
+
+-- IPCMessageHandlerPair(CLIENT)
|
|
1105
|
+
|
|
1106
|
+
Worker 3
|
|
1107
|
+
|
|
|
1108
|
+
+-- IPCMessageHandlerPair(CLIENT)
|
|
1109
|
+
```
|
|
1110
|
+
|
|
1111
|
+
---
|
|
1112
|
+
|
|
1113
|
+
# Difference from IPCMessageHandlerPair
|
|
1114
|
+
|
|
1115
|
+
`IPCMessageHandlerPairManager` and `IPCMessageHandlerPair` have deliberately different responsibilities.
|
|
1116
|
+
|
|
1117
|
+
## IPCMessageHandlerPair
|
|
1118
|
+
|
|
1119
|
+
Represents one IPC relationship.
|
|
1120
|
+
|
|
1121
|
+
```text
|
|
1122
|
+
Primary <----------> Worker
|
|
1123
|
+
```
|
|
1124
|
+
|
|
1125
|
+
It handles:
|
|
1126
|
+
|
|
1127
|
+
- one worker;
|
|
1128
|
+
- message sending;
|
|
1129
|
+
- message receiving;
|
|
1130
|
+
- event dispatch;
|
|
1131
|
+
- request/response communication.
|
|
1132
|
+
|
|
1133
|
+
---
|
|
1134
|
+
|
|
1135
|
+
## IPCMessageHandlerPairManager
|
|
1136
|
+
|
|
1137
|
+
Represents a collection of those relationships.
|
|
1138
|
+
|
|
1139
|
+
```text
|
|
1140
|
+
Manager
|
|
1141
|
+
│
|
|
1142
|
+
├── Pair -> Worker 1
|
|
1143
|
+
├── Pair -> Worker 2
|
|
1144
|
+
└── Pair -> Worker 3
|
|
1145
|
+
```
|
|
1146
|
+
|
|
1147
|
+
It handles:
|
|
1148
|
+
|
|
1149
|
+
- worker collection;
|
|
1150
|
+
- pair creation;
|
|
1151
|
+
- pair removal;
|
|
1152
|
+
- targeted worker selection;
|
|
1153
|
+
- broadcasts;
|
|
1154
|
+
- event propagation;
|
|
1155
|
+
- worker cleanup.
|
|
1156
|
+
|
|
1157
|
+
---
|
|
1158
|
+
|
|
1159
|
+
# Difference from IPCMessageHandler
|
|
1160
|
+
|
|
1161
|
+
`IPCMessageHandlerPairManager` replaces the multi-worker responsibilities that were previously built directly into `IPCMessageHandler`.
|
|
1162
|
+
|
|
1163
|
+
## IPCMessageHandler
|
|
1164
|
+
|
|
1165
|
+
The old model combines:
|
|
1166
|
+
|
|
1167
|
+
```text
|
|
1168
|
+
worker collection
|
|
1169
|
+
+
|
|
1170
|
+
IPC connection handling
|
|
1171
|
+
+
|
|
1172
|
+
broadcasting
|
|
1173
|
+
+
|
|
1174
|
+
event handling
|
|
1175
|
+
```
|
|
1176
|
+
|
|
1177
|
+
inside one class.
|
|
1178
|
+
|
|
1179
|
+
Conceptually:
|
|
1180
|
+
|
|
1181
|
+
```text
|
|
1182
|
+
IPCMessageHandler
|
|
1183
|
+
│
|
|
1184
|
+
├── Worker 1
|
|
1185
|
+
├── Worker 2
|
|
1186
|
+
└── Worker 3
|
|
1187
|
+
```
|
|
1188
|
+
|
|
1189
|
+
---
|
|
1190
|
+
|
|
1191
|
+
## IPCMessageHandlerPairManager
|
|
1192
|
+
|
|
1193
|
+
The pair-manager model separates the responsibilities:
|
|
1194
|
+
|
|
1195
|
+
```text
|
|
1196
|
+
IPCMessageHandlerPairManager
|
|
1197
|
+
│
|
|
1198
|
+
├── IPCMessageHandlerPair -> Worker 1
|
|
1199
|
+
├── IPCMessageHandlerPair -> Worker 2
|
|
1200
|
+
└── IPCMessageHandlerPair -> Worker 3
|
|
1201
|
+
```
|
|
1202
|
+
|
|
1203
|
+
The manager manages the collection.
|
|
1204
|
+
|
|
1205
|
+
Each pair manages one connection.
|
|
1206
|
+
|
|
1207
|
+
---
|
|
1208
|
+
|
|
1209
|
+
# Comparison
|
|
1210
|
+
|
|
1211
|
+
| Feature | IPCMessageHandlerPairManager | IPCMessageHandlerPair | IPCMessageHandler |
|
|
1212
|
+
| -------------------------------- | ---------------------------- | -------------------------- | ---------------------------- |
|
|
1213
|
+
| Primary purpose | Manage many IPC pairs | Manage one IPC connection | Manage many workers directly |
|
|
1214
|
+
| Relationship | One-to-many via pairs | One-to-one | One-to-many |
|
|
1215
|
+
| Stores worker collection | Yes | No | Yes |
|
|
1216
|
+
| Stores one worker | Per pair | Yes | No |
|
|
1217
|
+
| Creates pair per worker | Yes | N/A | No |
|
|
1218
|
+
| Target one worker | Yes | Naturally | Not its main model |
|
|
1219
|
+
| Broadcast | Yes | No | Yes |
|
|
1220
|
+
| Event propagation | Across all pairs | One pair only | Internal collection |
|
|
1221
|
+
| Future-worker event registration | Yes | N/A | N/A |
|
|
1222
|
+
| Automatic worker cleanup | Yes | No manager-level lifecycle | Manual client removal |
|
|
1223
|
+
| Separation of concerns | Strong | Strong | More combined |
|
|
1224
|
+
| Recommended server abstraction | Yes | Used by manager | Older combined model |
|
|
1225
|
+
|
|
1226
|
+
---
|
|
1227
|
+
|
|
1228
|
+
# Recommended Responsibility Model
|
|
1229
|
+
|
|
1230
|
+
The intended architecture is:
|
|
1231
|
+
|
|
1232
|
+
```text
|
|
1233
|
+
Process / Worker Manager
|
|
1234
|
+
|
|
|
1235
|
+
v
|
|
1236
|
+
IPCMessageHandlerPairManager
|
|
1237
|
+
|
|
|
1238
|
+
+-------------------+
|
|
1239
|
+
| |
|
|
1240
|
+
v v
|
|
1241
|
+
IPCMessageHandlerPair IPCMessageHandlerPair
|
|
1242
|
+
| |
|
|
1243
|
+
v v
|
|
1244
|
+
MessagingManager MessagingManager
|
|
1245
|
+
| |
|
|
1246
|
+
v v
|
|
1247
|
+
Worker 1 Worker 2
|
|
1248
|
+
```
|
|
1249
|
+
|
|
1250
|
+
Responsibilities should remain:
|
|
1251
|
+
|
|
1252
|
+
```text
|
|
1253
|
+
Process Manager
|
|
1254
|
+
-> decides when workers should exist
|
|
1255
|
+
|
|
1256
|
+
IPCMessageHandlerPairManager
|
|
1257
|
+
-> manages IPC relationships for those workers
|
|
1258
|
+
|
|
1259
|
+
IPCMessageHandlerPair
|
|
1260
|
+
-> manages one IPC relationship
|
|
1261
|
+
|
|
1262
|
+
MessagingManager
|
|
1263
|
+
-> manages the message protocol
|
|
1264
|
+
```
|
|
1265
|
+
|
|
1266
|
+
---
|
|
1267
|
+
|
|
1268
|
+
# When to Use IPCMessageHandlerPairManager
|
|
1269
|
+
|
|
1270
|
+
Use `IPCMessageHandlerPairManager` on the cluster primary/server side when:
|
|
1271
|
+
|
|
1272
|
+
- multiple workers exist;
|
|
1273
|
+
- each worker should have its own `IPCMessageHandlerPair`;
|
|
1274
|
+
- individual workers must be addressable;
|
|
1275
|
+
- broadcasts are required;
|
|
1276
|
+
- worker lifecycle cleanup should be centralized;
|
|
1277
|
+
- event registrations should automatically apply to every pair.
|
|
1278
|
+
|
|
1279
|
+
The key distinction is:
|
|
1280
|
+
|
|
1281
|
+
```text
|
|
1282
|
+
IPCMessageHandlerPair
|
|
1283
|
+
= "this worker connection"
|
|
1284
|
+
|
|
1285
|
+
IPCMessageHandlerPairManager
|
|
1286
|
+
= "all of my worker connections"
|
|
1287
|
+
```
|
|
1288
|
+
|
|
1289
|
+
This makes the pair manager the natural server-side abstraction for managing IPC communication across a Node.js worker cluster.
|