@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,702 @@
|
|
|
1
|
+
# IPCMessageHandlerPair
|
|
2
|
+
|
|
3
|
+
`IPCMessageHandlerPair` provides IPC-based request/response and event messaging between a Node.js cluster primary process and **one specific worker process**.
|
|
4
|
+
|
|
5
|
+
It is built on top of `MessagingManager` and exposes an event-oriented API using `on()`, `off()`, `emit()`, and `emitNoResponse()`.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Use `IPCMessageHandlerPair` when each handler instance should represent a **single primary-to-worker IPC relationship**.
|
|
12
|
+
|
|
13
|
+
Typical topology:
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
Primary <----------> Worker
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
For multiple workers, create or maintain multiple pair instances:
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
Worker Manager
|
|
23
|
+
│
|
|
24
|
+
├── Pair 1 <-------> Worker 1
|
|
25
|
+
├── Pair 2 <-------> Worker 2
|
|
26
|
+
└── Pair 3 <-------> Worker 3
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The class does not maintain an internal collection of workers.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Key Characteristics
|
|
34
|
+
|
|
35
|
+
- Supports `SERVER` and `CLIENT` roles.
|
|
36
|
+
- Designed around **one server/primary to one worker**.
|
|
37
|
+
- Stores one worker reference.
|
|
38
|
+
- Server-side `Start(worker)` associates the handler with that worker.
|
|
39
|
+
- Server-side `SendMessage()` sends to that one worker.
|
|
40
|
+
- Server-side `emit()` sends to that one worker.
|
|
41
|
+
- Uses `MessagingManager` for request/response message handling.
|
|
42
|
+
- Supports event registration through `on()` and `off()`.
|
|
43
|
+
- Supports request messages that expect a response.
|
|
44
|
+
- Supports fire-and-forget request messages through `emitNoResponse()`.
|
|
45
|
+
- Does not perform server-side broadcast management.
|
|
46
|
+
- Does not maintain a collection of cluster workers.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
# Constructor
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
new IPCMessageHandlerPair(options);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Options
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
export interface IPCMessageHandlerPairOptions {
|
|
60
|
+
logger: ISTSLogger;
|
|
61
|
+
requestResponseMessageTimeout: number;
|
|
62
|
+
namespace: string;
|
|
63
|
+
role: "SERVER" | "CLIENT";
|
|
64
|
+
ignoreEvents?: string[];
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### `logger`
|
|
69
|
+
|
|
70
|
+
Logger used when event emission or message processing fails.
|
|
71
|
+
|
|
72
|
+
### `requestResponseMessageTimeout`
|
|
73
|
+
|
|
74
|
+
Maximum time allowed for request/response messages.
|
|
75
|
+
|
|
76
|
+
### `namespace`
|
|
77
|
+
|
|
78
|
+
Namespace supplied to the underlying `MessagingManager`.
|
|
79
|
+
|
|
80
|
+
### `role`
|
|
81
|
+
|
|
82
|
+
Determines which side of the IPC relationship is configured.
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
role: "SERVER";
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Represents the primary/server side.
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
role: "CLIENT";
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Represents the worker/client side.
|
|
95
|
+
|
|
96
|
+
### `ignoreEvents`
|
|
97
|
+
|
|
98
|
+
Optional list of event names whose errors should be ignored by `emit()`.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
# Server Role
|
|
103
|
+
|
|
104
|
+
When configured with:
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
role: "SERVER";
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
the handler is associated with one worker.
|
|
111
|
+
|
|
112
|
+
The class stores:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
#worker;
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
and the worker relationship is established through:
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
Start(worker);
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
# Server-side Message Receiver
|
|
127
|
+
|
|
128
|
+
The server-side implementation registers a `"message"` listener directly on the worker.
|
|
129
|
+
|
|
130
|
+
Conceptually:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
worker.on("message", handler);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Incoming messages are passed to:
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
MessagingManager.ProcessMessage(...)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
with the associated worker supplied as message context.
|
|
143
|
+
|
|
144
|
+
This gives the pair a direct relationship between:
|
|
145
|
+
|
|
146
|
+
```text
|
|
147
|
+
one IPCMessageHandlerPair
|
|
148
|
+
|
|
|
149
|
+
v
|
|
150
|
+
one Worker
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
# Client Role
|
|
156
|
+
|
|
157
|
+
When configured with:
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
role: "CLIENT";
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
the handler runs inside the worker process.
|
|
164
|
+
|
|
165
|
+
Outgoing messages use Node.js process IPC:
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
process.send(...)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Incoming messages use:
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
process.on("message", ...)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
The client side therefore communicates with its parent process.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
# Start()
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
pair.Start(worker);
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
For a server-side pair, `Start()` associates the handler with one worker.
|
|
188
|
+
|
|
189
|
+
Example:
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
const pair = new IPCMessageHandlerPair({
|
|
193
|
+
logger,
|
|
194
|
+
requestResponseMessageTimeout: 5000,
|
|
195
|
+
namespace: "worker-1",
|
|
196
|
+
role: "SERVER",
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
pair.Start(worker);
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
The handler then stores the worker reference and starts the underlying `MessagingManager` with it.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Client-side Start()
|
|
207
|
+
|
|
208
|
+
A worker/client does not need to supply a worker object:
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
pair.Start();
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
The client communicates with its parent through `process.send()` and `process.on("message")`.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
# Stop()
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
pair.Stop();
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
When a worker is associated with the pair, `Stop()`:
|
|
225
|
+
|
|
226
|
+
1. Stops `MessagingManager` using the worker context.
|
|
227
|
+
2. Removes the worker message receiver through the configured messaging callbacks.
|
|
228
|
+
3. Clears the stored worker reference.
|
|
229
|
+
|
|
230
|
+
Conceptually:
|
|
231
|
+
|
|
232
|
+
```text
|
|
233
|
+
Before:
|
|
234
|
+
|
|
235
|
+
IPCMessageHandlerPair ---> Worker
|
|
236
|
+
|
|
237
|
+
After Stop():
|
|
238
|
+
|
|
239
|
+
IPCMessageHandlerPair Worker
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
# worker
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
pair.worker;
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Returns the worker currently associated with the pair.
|
|
251
|
+
|
|
252
|
+
The value is `null` when no server-side worker is attached.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
# SendMessage()
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
await pair.SendMessage(payload);
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Sends a request message through the underlying `MessagingManager`.
|
|
263
|
+
|
|
264
|
+
## Server behavior
|
|
265
|
+
|
|
266
|
+
If a worker has been supplied through:
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
pair.Start(worker);
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
the message is sent specifically to that worker.
|
|
273
|
+
|
|
274
|
+
```text
|
|
275
|
+
Primary
|
|
276
|
+
|
|
|
277
|
+
v
|
|
278
|
+
Worker
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
There is no iteration over a worker collection.
|
|
282
|
+
|
|
283
|
+
There is no built-in broadcast.
|
|
284
|
+
|
|
285
|
+
There is no `Promise.all()` aggregation of responses from multiple workers.
|
|
286
|
+
|
|
287
|
+
## Client behavior
|
|
288
|
+
|
|
289
|
+
When no worker is stored, the message is sent using the client-side messaging configuration, which uses:
|
|
290
|
+
|
|
291
|
+
```ts
|
|
292
|
+
process.send(...)
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
to communicate with the primary process.
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
# Event Registration
|
|
300
|
+
|
|
301
|
+
## on()
|
|
302
|
+
|
|
303
|
+
```ts
|
|
304
|
+
pair.on(eventName, callback);
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Registers an IPC event callback.
|
|
308
|
+
|
|
309
|
+
Example:
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
pair.on("get-status", (callback) => {
|
|
313
|
+
callback({
|
|
314
|
+
pid: process.pid,
|
|
315
|
+
status: "OK",
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Only one event callback is retained for a given event name.
|
|
321
|
+
|
|
322
|
+
Registering the same event again replaces the existing callback.
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## off()
|
|
327
|
+
|
|
328
|
+
```ts
|
|
329
|
+
pair.off(eventName);
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Removes an event callback.
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
# emit()
|
|
337
|
+
|
|
338
|
+
```ts
|
|
339
|
+
pair.emit(eventName, ...args, callback);
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Sends an event that expects a response.
|
|
343
|
+
|
|
344
|
+
Example:
|
|
345
|
+
|
|
346
|
+
```ts
|
|
347
|
+
pair.emit("get-status", (response) => {
|
|
348
|
+
console.log(response);
|
|
349
|
+
});
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Internally, the event is represented as a message payload containing:
|
|
353
|
+
|
|
354
|
+
```ts
|
|
355
|
+
{
|
|
356
|
+
__eventName: eventName,
|
|
357
|
+
args: [...]
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
The final argument is used as the response callback.
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## Server-side emit behavior
|
|
366
|
+
|
|
367
|
+
A server-side `emit()` targets **the single worker associated with this pair**.
|
|
368
|
+
|
|
369
|
+
```text
|
|
370
|
+
IPCMessageHandlerPair
|
|
371
|
+
|
|
|
372
|
+
v
|
|
373
|
+
Worker
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
If the primary needs to emit the same event to three workers, the surrounding manager must invoke the corresponding three pair instances.
|
|
377
|
+
|
|
378
|
+
For example:
|
|
379
|
+
|
|
380
|
+
```ts
|
|
381
|
+
for (const pair of workerPairs.values()) {
|
|
382
|
+
pair.emit("refresh-config", callback);
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
Broadcasting is therefore a responsibility of the owner of the pair collection rather than of `IPCMessageHandlerPair` itself.
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
# emitNoResponse()
|
|
391
|
+
|
|
392
|
+
```ts
|
|
393
|
+
await pair.emitNoResponse(eventName, ...args);
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
Sends a fire-and-forget event.
|
|
397
|
+
|
|
398
|
+
No response callback is required.
|
|
399
|
+
|
|
400
|
+
Conceptually:
|
|
401
|
+
|
|
402
|
+
```text
|
|
403
|
+
Pair ------> remote process
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
Unlike `IPCMessageHandler`, this class does not iterate over an internal worker collection.
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
# Message Processing
|
|
411
|
+
|
|
412
|
+
Incoming request messages are handled by `#processPayload()`.
|
|
413
|
+
|
|
414
|
+
The payload identifies the event using:
|
|
415
|
+
|
|
416
|
+
```ts
|
|
417
|
+
requestPayload.__eventName;
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
The registered callback is retrieved from the internal event map.
|
|
421
|
+
|
|
422
|
+
Supported request types include:
|
|
423
|
+
|
|
424
|
+
```text
|
|
425
|
+
REQUEST
|
|
426
|
+
REQUEST_NO_RESPONSE
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## REQUEST
|
|
432
|
+
|
|
433
|
+
The event callback is given the request arguments followed by a response callback.
|
|
434
|
+
|
|
435
|
+
Conceptually:
|
|
436
|
+
|
|
437
|
+
```ts
|
|
438
|
+
pair.on("get-status", (...args, callback) => {
|
|
439
|
+
callback({
|
|
440
|
+
status: "OK",
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
## REQUEST_NO_RESPONSE
|
|
448
|
+
|
|
449
|
+
The registered callback is invoked with only the supplied event arguments.
|
|
450
|
+
|
|
451
|
+
No response is expected.
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
# Typical Primary Usage
|
|
456
|
+
|
|
457
|
+
```ts
|
|
458
|
+
const pair = new IPCMessageHandlerPair({
|
|
459
|
+
logger,
|
|
460
|
+
requestResponseMessageTimeout: 5000,
|
|
461
|
+
namespace: "worker-1",
|
|
462
|
+
role: "SERVER",
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
pair.Start(worker);
|
|
466
|
+
|
|
467
|
+
pair.emit("get-status", (response) => {
|
|
468
|
+
console.log(response);
|
|
469
|
+
});
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
The message is sent only to the worker associated with `pair`.
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
# Typical Worker Usage
|
|
477
|
+
|
|
478
|
+
```ts
|
|
479
|
+
const pair = new IPCMessageHandlerPair({
|
|
480
|
+
logger,
|
|
481
|
+
requestResponseMessageTimeout: 5000,
|
|
482
|
+
namespace: "worker-1",
|
|
483
|
+
role: "CLIENT",
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
pair.on("get-status", (callback) => {
|
|
487
|
+
callback({
|
|
488
|
+
pid: process.pid,
|
|
489
|
+
status: "OK",
|
|
490
|
+
});
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
pair.Start();
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
# Managing Multiple Workers
|
|
499
|
+
|
|
500
|
+
`IPCMessageHandlerPair` intentionally does not maintain a worker collection.
|
|
501
|
+
|
|
502
|
+
A higher-level process manager can maintain the collection instead.
|
|
503
|
+
|
|
504
|
+
For example:
|
|
505
|
+
|
|
506
|
+
```ts
|
|
507
|
+
const workerPairs = new Map<number, IPCMessageHandlerPair>();
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
Conceptually:
|
|
511
|
+
|
|
512
|
+
```text
|
|
513
|
+
WorkerProcessManager
|
|
514
|
+
│
|
|
515
|
+
├── Worker 1
|
|
516
|
+
│ └── IPCMessageHandlerPair
|
|
517
|
+
│
|
|
518
|
+
├── Worker 2
|
|
519
|
+
│ └── IPCMessageHandlerPair
|
|
520
|
+
│
|
|
521
|
+
└── Worker 3
|
|
522
|
+
└── IPCMessageHandlerPair
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
This separates two responsibilities:
|
|
526
|
+
|
|
527
|
+
```text
|
|
528
|
+
WorkerProcessManager
|
|
529
|
+
-> owns workers
|
|
530
|
+
-> handles worker lifecycle
|
|
531
|
+
-> performs broadcast operations
|
|
532
|
+
|
|
533
|
+
IPCMessageHandlerPair
|
|
534
|
+
-> owns one IPC relationship
|
|
535
|
+
-> handles messages
|
|
536
|
+
-> handles request/response correlation
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
---
|
|
540
|
+
|
|
541
|
+
# Difference from IPCMessageHandler
|
|
542
|
+
|
|
543
|
+
This is the most important distinction.
|
|
544
|
+
|
|
545
|
+
## IPCMessageHandlerPair is one-to-one
|
|
546
|
+
|
|
547
|
+
One pair represents one worker relationship:
|
|
548
|
+
|
|
549
|
+
```text
|
|
550
|
+
Primary <----------> Worker
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
It stores one worker:
|
|
554
|
+
|
|
555
|
+
```ts
|
|
556
|
+
#worker;
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
and the server associates that worker with:
|
|
560
|
+
|
|
561
|
+
```ts
|
|
562
|
+
Start(worker);
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
A message from the server is sent only to that worker.
|
|
566
|
+
|
|
567
|
+
---
|
|
568
|
+
|
|
569
|
+
## IPCMessageHandler is one-to-many
|
|
570
|
+
|
|
571
|
+
`IPCMessageHandler` owns a collection:
|
|
572
|
+
|
|
573
|
+
```ts
|
|
574
|
+
#clients;
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
Workers are added with:
|
|
578
|
+
|
|
579
|
+
```ts
|
|
580
|
+
AddClient(worker);
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
and removed with:
|
|
584
|
+
|
|
585
|
+
```ts
|
|
586
|
+
RemoveClient(id);
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
Its topology is:
|
|
590
|
+
|
|
591
|
+
```text
|
|
592
|
+
Worker 1
|
|
593
|
+
/
|
|
594
|
+
Primary ---------- Worker 2
|
|
595
|
+
\
|
|
596
|
+
Worker 3
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
When the server calls:
|
|
600
|
+
|
|
601
|
+
```ts
|
|
602
|
+
SendMessage(...)
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
the handler iterates through its worker collection and sends the message to all registered workers.
|
|
606
|
+
|
|
607
|
+
---
|
|
608
|
+
|
|
609
|
+
# Responsibility Difference
|
|
610
|
+
|
|
611
|
+
This distinction is architectural, not merely a difference in method names.
|
|
612
|
+
|
|
613
|
+
## IPCMessageHandlerPair
|
|
614
|
+
|
|
615
|
+
```text
|
|
616
|
+
one connection
|
|
617
|
+
+
|
|
618
|
+
messaging
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
The class represents a single IPC relationship.
|
|
622
|
+
|
|
623
|
+
A higher-level manager is responsible for:
|
|
624
|
+
|
|
625
|
+
```text
|
|
626
|
+
worker collection
|
|
627
|
+
broadcasting
|
|
628
|
+
worker lifecycle
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
## IPCMessageHandler
|
|
632
|
+
|
|
633
|
+
```text
|
|
634
|
+
worker collection
|
|
635
|
+
+
|
|
636
|
+
messaging
|
|
637
|
+
+
|
|
638
|
+
broadcasting
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
Those responsibilities are combined inside the handler.
|
|
642
|
+
|
|
643
|
+
---
|
|
644
|
+
|
|
645
|
+
# Comparison
|
|
646
|
+
|
|
647
|
+
| Feature | IPCMessageHandlerPair | IPCMessageHandler |
|
|
648
|
+
| ------------------------------------------ | ------------------------ | -------------------------- |
|
|
649
|
+
| Relationship | One-to-one | One-to-many |
|
|
650
|
+
| Number of server-side workers per instance | One | Many |
|
|
651
|
+
| Worker storage | Single `#worker` | `#clients` collection |
|
|
652
|
+
| Attach worker | `Start(worker)` | `AddClient(worker)` |
|
|
653
|
+
| Detach worker | `Stop()` | `RemoveClient(id)` |
|
|
654
|
+
| Server `SendMessage()` | One worker | All workers |
|
|
655
|
+
| Server `emit()` | One worker | All workers |
|
|
656
|
+
| Server `emitNoResponse()` | One target | All workers |
|
|
657
|
+
| Multiple-response aggregation | No | Yes, using `Promise.all()` |
|
|
658
|
+
| Built-in worker collection | No | Yes |
|
|
659
|
+
| Built-in broadcasting | No | Yes |
|
|
660
|
+
| External manager naturally owns workers | Yes | Not required |
|
|
661
|
+
| Best abstraction | "this worker connection" | "my worker cluster" |
|
|
662
|
+
|
|
663
|
+
---
|
|
664
|
+
|
|
665
|
+
# When to Use IPCMessageHandlerPair
|
|
666
|
+
|
|
667
|
+
Use `IPCMessageHandlerPair` when the surrounding process manager already knows which workers exist and should remain responsible for worker lifecycle.
|
|
668
|
+
|
|
669
|
+
It is particularly appropriate when the desired abstraction is:
|
|
670
|
+
|
|
671
|
+
```text
|
|
672
|
+
"Send this message to this worker."
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
rather than:
|
|
676
|
+
|
|
677
|
+
```text
|
|
678
|
+
"Send this message to all workers."
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
It also provides a clean structure when each worker has other worker-specific state.
|
|
682
|
+
|
|
683
|
+
For example:
|
|
684
|
+
|
|
685
|
+
```ts
|
|
686
|
+
interface WorkerRecord {
|
|
687
|
+
worker: Worker;
|
|
688
|
+
ipc: IPCMessageHandlerPair;
|
|
689
|
+
startedAt: Date;
|
|
690
|
+
state: WorkerState;
|
|
691
|
+
}
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
The process manager can then choose whether to:
|
|
695
|
+
|
|
696
|
+
- address one worker;
|
|
697
|
+
- address a subset of workers;
|
|
698
|
+
- broadcast to every worker;
|
|
699
|
+
- remove a worker;
|
|
700
|
+
- replace a worker.
|
|
701
|
+
|
|
702
|
+
The IPC transport itself remains focused on the single primary/worker communication relationship.
|