@fluojs/microservices 1.0.4 → 2.0.0

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.
Files changed (37) hide show
  1. package/README.ko.md +64 -6
  2. package/README.md +64 -6
  3. package/dist/module.d.ts.map +1 -1
  4. package/dist/module.js +2 -1
  5. package/dist/service.d.ts +15 -5
  6. package/dist/service.d.ts.map +1 -1
  7. package/dist/service.js +96 -38
  8. package/dist/status.d.ts +3 -0
  9. package/dist/status.d.ts.map +1 -1
  10. package/dist/status.js +10 -2
  11. package/dist/transports/grpc-transport.d.ts +4 -2
  12. package/dist/transports/grpc-transport.d.ts.map +1 -1
  13. package/dist/transports/grpc-transport.js +241 -241
  14. package/dist/transports/kafka-transport.d.ts +9 -1
  15. package/dist/transports/kafka-transport.d.ts.map +1 -1
  16. package/dist/transports/kafka-transport.js +41 -21
  17. package/dist/transports/mqtt-transport.d.ts +1 -0
  18. package/dist/transports/mqtt-transport.d.ts.map +1 -1
  19. package/dist/transports/mqtt-transport.js +22 -1
  20. package/dist/transports/nats-transport.d.ts +3 -0
  21. package/dist/transports/nats-transport.d.ts.map +1 -1
  22. package/dist/transports/nats-transport.js +83 -30
  23. package/dist/transports/rabbitmq-transport.d.ts +10 -1
  24. package/dist/transports/rabbitmq-transport.d.ts.map +1 -1
  25. package/dist/transports/rabbitmq-transport.js +80 -30
  26. package/dist/transports/redis-streams-transport.d.ts +18 -0
  27. package/dist/transports/redis-streams-transport.d.ts.map +1 -1
  28. package/dist/transports/redis-streams-transport.js +46 -3
  29. package/dist/transports/redis-transport.d.ts +1 -1
  30. package/dist/transports/redis-transport.d.ts.map +1 -1
  31. package/dist/transports/redis-transport.js +32 -16
  32. package/dist/transports/tcp-transport.d.ts +1 -0
  33. package/dist/transports/tcp-transport.d.ts.map +1 -1
  34. package/dist/transports/tcp-transport.js +45 -44
  35. package/dist/types.d.ts +7 -0
  36. package/dist/types.d.ts.map +1 -1
  37. package/package.json +11 -7
@@ -1,3 +1,5 @@
1
+ import { logTransportEventHandlerFailure } from './event-handler-logger.js';
2
+
1
3
  /** Options for configuring the Kafka microservice transport. */
2
4
 
3
5
  /**
@@ -12,11 +14,28 @@ export class KafkaMicroserviceTransport {
12
14
  handler;
13
15
  listening = false;
14
16
  listenPromise;
17
+ logger;
15
18
  eventTopic;
16
19
  messageTopic;
17
20
  pending = new Map();
18
21
  requestTimeoutMs;
19
22
  responseTopic;
23
+ logEventHandlerFailure(error) {
24
+ try {
25
+ logTransportEventHandlerFailure(this.logger, 'KafkaMicroserviceTransport', error);
26
+ } catch {
27
+ // A failing logger must not mask the event failure the broker still has to observe.
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Registers the runtime logger that receives inbound event handler failures.
33
+ *
34
+ * @param logger Logger used to report event handler failures.
35
+ */
36
+ setLogger(logger) {
37
+ this.logger = logger;
38
+ }
20
39
 
21
40
  /**
22
41
  * Creates a Kafka transport with explicit producer and consumer collaborators.
@@ -55,17 +74,11 @@ export class KafkaMicroserviceTransport {
55
74
  this.listenPromise = (async () => {
56
75
  const subscribed = [];
57
76
  try {
58
- await this.options.consumer.subscribe(this.eventTopic, message => {
59
- void this.handleInboundEvent(message).catch(() => undefined);
60
- });
77
+ await this.options.consumer.subscribe(this.eventTopic, message => this.handleInboundEvent(message));
61
78
  subscribed.push(this.eventTopic);
62
- await this.options.consumer.subscribe(this.messageTopic, message => {
63
- void this.handleInboundRequest(message).catch(() => undefined);
64
- });
79
+ await this.options.consumer.subscribe(this.messageTopic, message => this.handleInboundRequest(message));
65
80
  subscribed.push(this.messageTopic);
66
- await this.options.consumer.subscribe(this.responseTopic, message => {
67
- void this.handleInboundResponse(message).catch(() => undefined);
68
- });
81
+ await this.options.consumer.subscribe(this.responseTopic, message => this.handleInboundResponse(message));
69
82
  subscribed.push(this.responseTopic);
70
83
  } catch (error) {
71
84
  for (const topic of subscribed) {
@@ -232,11 +245,16 @@ export class KafkaMicroserviceTransport {
232
245
  if (!message || message.kind !== 'event') {
233
246
  return;
234
247
  }
235
- await this.handler({
236
- kind: 'event',
237
- pattern: message.pattern,
238
- payload: message.payload
239
- });
248
+ try {
249
+ await this.handler({
250
+ kind: 'event',
251
+ pattern: message.pattern,
252
+ payload: message.payload
253
+ });
254
+ } catch (error) {
255
+ this.logEventHandlerFailure(error);
256
+ throw error;
257
+ }
240
258
  }
241
259
  async handleInboundRequest(rawMessage) {
242
260
  if (!this.handler) {
@@ -247,19 +265,14 @@ export class KafkaMicroserviceTransport {
247
265
  return;
248
266
  }
249
267
  const replyTopic = message.replyTopic && message.replyTopic.length > 0 ? message.replyTopic : this.responseTopic;
268
+ let payload;
250
269
  try {
251
- const payload = await this.handler({
270
+ payload = await this.handler({
252
271
  kind: 'message',
253
272
  pattern: message.pattern,
254
273
  payload: message.payload,
255
274
  requestId: message.requestId
256
275
  });
257
- await this.options.producer.publish(replyTopic, JSON.stringify({
258
- kind: 'response',
259
- pattern: message.pattern,
260
- payload,
261
- requestId: message.requestId
262
- }));
263
276
  } catch (error) {
264
277
  const errorMessage = error instanceof Error ? error.message : 'Unhandled microservice error';
265
278
  await this.options.producer.publish(replyTopic, JSON.stringify({
@@ -268,7 +281,14 @@ export class KafkaMicroserviceTransport {
268
281
  pattern: message.pattern,
269
282
  requestId: message.requestId
270
283
  }));
284
+ return;
271
285
  }
286
+ await this.options.producer.publish(replyTopic, JSON.stringify({
287
+ kind: 'response',
288
+ pattern: message.pattern,
289
+ payload,
290
+ requestId: message.requestId
291
+ }));
272
292
  }
273
293
  async handleInboundResponse(rawMessage) {
274
294
  const message = this.parseMessage(rawMessage);
@@ -121,6 +121,7 @@ export declare class MqttMicroserviceTransport implements MicroserviceTransport
121
121
  private subscribeTopic;
122
122
  private unsubscribeTopic;
123
123
  private endClient;
124
+ private disposeOwnedClientAfterListenFailure;
124
125
  private logEventHandlerFailure;
125
126
  }
126
127
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"mqtt-transport.d.ts","sourceRoot":"","sources":["../../src/transports/mqtt-transport.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mqtt-transport.d.ts","sourceRoot":"","sources":["../../src/transports/mqtt-transport.ts"],"names":[],"mappings":"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"}
@@ -102,6 +102,9 @@ export class MqttMicroserviceTransport {
102
102
  await this.unsubscribeTopic(client, topic).catch(() => undefined);
103
103
  }
104
104
  client.off?.('message', this.messageListener);
105
+ this.handler = undefined;
106
+ this.listening = false;
107
+ await this.disposeOwnedClientAfterListenFailure(client);
105
108
  throw error;
106
109
  }
107
110
  this.listening = true;
@@ -254,7 +257,11 @@ export class MqttMicroserviceTransport {
254
257
  this.closePromise = (async () => {
255
258
  let closeError;
256
259
  if (this.listenPromise) {
257
- await this.listenPromise;
260
+ try {
261
+ await this.listenPromise;
262
+ } catch (error) {
263
+ closeError = error;
264
+ }
258
265
  }
259
266
  try {
260
267
  const client = this.client;
@@ -457,6 +464,20 @@ export class MqttMicroserviceTransport {
457
464
  });
458
465
  });
459
466
  }
467
+ async disposeOwnedClientAfterListenFailure(client) {
468
+ if (!this.internallyOwnedClient) {
469
+ return;
470
+ }
471
+ try {
472
+ await this.endClient(client);
473
+ } catch {
474
+ // Preserve the original startup failure for callers; shutdown errors are best-effort here.
475
+ } finally {
476
+ if (this.client === client) {
477
+ this.client = undefined;
478
+ }
479
+ }
480
+ }
460
481
  logEventHandlerFailure(error) {
461
482
  logTransportEventHandlerFailure(this.logger, 'MqttMicroserviceTransport', error);
462
483
  }
@@ -35,6 +35,7 @@ export interface NatsMicroserviceTransportOptions {
35
35
  */
36
36
  export declare class NatsMicroserviceTransport implements MicroserviceTransport {
37
37
  private readonly options;
38
+ private closePromise;
38
39
  private closing;
39
40
  private handler;
40
41
  private logger;
@@ -46,6 +47,8 @@ export declare class NatsMicroserviceTransport implements MicroserviceTransport
46
47
  private subscriptions;
47
48
  private logEventHandlerFailure;
48
49
  private handleEventMessageSafely;
50
+ private handleRequestMessageSafely;
51
+ private logRequestCallbackFailure;
49
52
  /**
50
53
  * Creates a NATS transport using a client and codec supplied by the application.
51
54
  *
@@ -1 +1 @@
1
- {"version":3,"file":"nats-transport.d.ts","sourceRoot":"","sources":["../../src/transports/nats-transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,2BAA2B,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGxG,UAAU,eAAe;IACvB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;CACjC;AAED,UAAU,aAAa;IACrB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC;IACjC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC;CACnC;AAED,UAAU,oBAAoB;IAC5B,WAAW,IAAI,IAAI,CAAC;CACrB;AAED,UAAU,QAAQ;IAChB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI,CAAC;IACpD,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,UAAU,CAAA;KAAE,CAAC,CAAC;IAC7G,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,GAAG,oBAAoB,CAAC;CAC/F;AAED,+DAA+D;AAC/D,MAAM,WAAW,gCAAgC;IAC/C,MAAM,EAAE,QAAQ,CAAC;IACjB,KAAK,EAAE,aAAa,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAkBD;;;;;GAKG;AACH,qBAAa,yBAA0B,YAAW,qBAAqB;IA0BzD,OAAO,CAAC,QAAQ,CAAC,OAAO;IAzBpC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,MAAM,CAA0C;IACxD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAC7D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,aAAa,CAA8B;IAEnD,OAAO,CAAC,sBAAsB;IAI9B,OAAO,CAAC,wBAAwB;IAMhC;;;;OAIG;gBAC0B,OAAO,EAAE,gCAAgC;IAMtE,SAAS,CAAC,MAAM,EAAE,2BAA2B,GAAG,IAAI;IAIpD;;;;;OAKG;IACG,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBtD;;;;;;;OAOG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IA+FrF;;;;;;OAMG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAc5D;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YA0Bd,kBAAkB;YAsBlB,oBAAoB;IAwBlC,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,MAAM;CAGf"}
1
+ {"version":3,"file":"nats-transport.d.ts","sourceRoot":"","sources":["../../src/transports/nats-transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,2BAA2B,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGxG,UAAU,eAAe;IACvB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;CACjC;AAED,UAAU,aAAa;IACrB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC;IACjC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC;CACnC;AAED,UAAU,oBAAoB;IAC5B,WAAW,IAAI,IAAI,CAAC;CACrB;AAED,UAAU,QAAQ;IAChB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI,CAAC;IACpD,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,UAAU,CAAA;KAAE,CAAC,CAAC;IAC7G,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,GAAG,oBAAoB,CAAC;CAC/F;AAED,+DAA+D;AAC/D,MAAM,WAAW,gCAAgC;IAC/C,MAAM,EAAE,QAAQ,CAAC;IACjB,KAAK,EAAE,aAAa,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAkBD;;;;;GAKG;AACH,qBAAa,yBAA0B,YAAW,qBAAqB;IA+CzD,OAAO,CAAC,QAAQ,CAAC,OAAO;IA9CpC,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,MAAM,CAA0C;IACxD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAC7D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,aAAa,CAA8B;IAEnD,OAAO,CAAC,sBAAsB;IAI9B,OAAO,CAAC,wBAAwB;IAMhC,OAAO,CAAC,0BAA0B;IAMlC,OAAO,CAAC,yBAAyB;IAcjC;;;;OAIG;gBAC0B,OAAO,EAAE,gCAAgC;IAMtE,SAAS,CAAC,MAAM,EAAE,2BAA2B,GAAG,IAAI;IAIpD;;;;;OAKG;IACG,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IA4CtD;;;;;;;OAOG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IA+FrF;;;;;;OAMG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAc5D;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YA+Cd,kBAAkB;YAsBlB,oBAAoB;IA8BlC,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,MAAM;CAGf"}
@@ -9,6 +9,7 @@ import { logTransportEventHandlerFailure } from './event-handler-logger.js';
9
9
  * preserving JSON framing and NATS request timeout behavior.
10
10
  */
11
11
  export class NatsMicroserviceTransport {
12
+ closePromise;
12
13
  closing = false;
13
14
  handler;
14
15
  logger;
@@ -26,6 +27,22 @@ export class NatsMicroserviceTransport {
26
27
  this.logEventHandlerFailure(error);
27
28
  });
28
29
  }
30
+ handleRequestMessageSafely(message) {
31
+ void this.handleRequestMessage(message).catch(error => {
32
+ this.logRequestCallbackFailure(error);
33
+ });
34
+ }
35
+ logRequestCallbackFailure(error) {
36
+ const logger = this.logger;
37
+ if (!logger) {
38
+ return;
39
+ }
40
+ try {
41
+ logger.error('Request callback failed.', error, 'NatsMicroserviceTransport');
42
+ } catch (loggerError) {
43
+ void loggerError;
44
+ }
45
+ }
29
46
 
30
47
  /**
31
48
  * Creates a NATS transport using a client and codec supplied by the application.
@@ -49,18 +66,39 @@ export class NatsMicroserviceTransport {
49
66
  * @returns A promise that resolves once subscriptions are active.
50
67
  */
51
68
  async listen(handler) {
52
- this.closing = false;
69
+ if (this.closing) {
70
+ if (this.closePromise) {
71
+ throw new Error('NATS microservice transport is closing. Wait for close() to complete before listen().');
72
+ }
73
+ if (this.subscriptions.length > 0) {
74
+ throw new Error('NATS subscription cleanup is incomplete. Call close() again before listen().');
75
+ }
76
+ this.closing = false;
77
+ }
53
78
  this.handler = handler;
54
79
  if (this.listening) {
55
80
  return;
56
81
  }
57
- const eventSubscription = this.options.client.subscribe(this.eventSubject, message => {
58
- this.handleEventMessageSafely(message);
59
- });
60
- const messageSubscription = this.options.client.subscribe(this.messageSubject, message => {
61
- void this.handleRequestMessage(message);
62
- });
63
- this.subscriptions = [eventSubscription, messageSubscription];
82
+ try {
83
+ this.subscriptions.push(this.options.client.subscribe(this.eventSubject, message => {
84
+ this.handleEventMessageSafely(message);
85
+ }));
86
+ this.subscriptions.push(this.options.client.subscribe(this.messageSubject, message => {
87
+ this.handleRequestMessageSafely(message);
88
+ }));
89
+ } catch (error) {
90
+ for (const subscription of this.subscriptions.reverse()) {
91
+ try {
92
+ subscription.unsubscribe();
93
+ } catch {
94
+ // Preserve the original subscription failure; partial setup cleanup is best-effort.
95
+ }
96
+ }
97
+ this.subscriptions = [];
98
+ this.handler = undefined;
99
+ this.listening = false;
100
+ throw error;
101
+ }
64
102
  this.listening = true;
65
103
  }
66
104
 
@@ -173,24 +211,39 @@ export class NatsMicroserviceTransport {
173
211
  * @returns A promise that resolves once shutdown cleanup completes.
174
212
  */
175
213
  async close() {
214
+ if (this.closePromise) {
215
+ await this.closePromise;
216
+ return;
217
+ }
176
218
  this.closing = true;
177
- let closeError;
178
- try {
219
+ this.closePromise = (async () => {
220
+ const cleanupErrors = [];
221
+ const retainedSubscriptions = [];
179
222
  for (const subscription of this.subscriptions) {
180
- subscription.unsubscribe();
223
+ try {
224
+ subscription.unsubscribe();
225
+ } catch (error) {
226
+ cleanupErrors.push(error);
227
+ retainedSubscriptions.push(subscription);
228
+ }
181
229
  }
182
- } catch (error) {
183
- closeError = error;
184
- } finally {
185
- this.subscriptions = [];
230
+ this.subscriptions = retainedSubscriptions;
186
231
  this.listening = false;
187
232
  this.handler = undefined;
188
233
  for (const pending of [...this.pending.values()]) {
189
234
  pending.reject(new Error('NATS microservice transport closed before response.'));
190
235
  }
191
- }
192
- if (closeError) {
193
- throw closeError;
236
+ if (cleanupErrors.length === 1) {
237
+ throw cleanupErrors[0];
238
+ }
239
+ if (cleanupErrors.length > 1) {
240
+ throw new AggregateError(cleanupErrors, 'NATS subscription cleanup failed for multiple subscriptions.');
241
+ }
242
+ })();
243
+ try {
244
+ await this.closePromise;
245
+ } finally {
246
+ this.closePromise = undefined;
194
247
  }
195
248
  }
196
249
  async handleEventMessage(message) {
@@ -219,21 +272,21 @@ export class NatsMicroserviceTransport {
219
272
  if (packet.kind !== 'message') {
220
273
  return;
221
274
  }
275
+ let response;
222
276
  try {
223
- const payload = await this.handler({
224
- kind: 'message',
225
- pattern: packet.pattern,
226
- payload: packet.payload
227
- });
228
- message.respond(this.encode({
229
- payload
230
- }));
277
+ response = {
278
+ payload: await this.handler({
279
+ kind: 'message',
280
+ pattern: packet.pattern,
281
+ payload: packet.payload
282
+ })
283
+ };
231
284
  } catch (error) {
232
- const errorMessage = error instanceof Error ? error.message : 'Unhandled microservice error';
233
- message.respond(this.encode({
234
- error: errorMessage
235
- }));
285
+ response = {
286
+ error: error instanceof Error ? error.message : 'Unhandled microservice error'
287
+ };
236
288
  }
289
+ message.respond(this.encode(response));
237
290
  }
238
291
  decode(data) {
239
292
  return JSON.parse(this.options.codec.decode(data));
@@ -1,4 +1,4 @@
1
- import type { MicroserviceTransport, TransportHandler } from '../types.js';
1
+ import type { MicroserviceTransport, MicroserviceTransportLogger, TransportHandler } from '../types.js';
2
2
  interface RabbitMqConsumerLike {
3
3
  consume(queue: string, handler: (message: string) => Promise<void> | void): Promise<void>;
4
4
  cancel(queue: string): Promise<void>;
@@ -23,16 +23,25 @@ export interface RabbitMqMicroserviceTransportOptions {
23
23
  */
24
24
  export declare class RabbitMqMicroserviceTransport implements MicroserviceTransport {
25
25
  private readonly options;
26
+ private closePromise;
26
27
  private closing;
27
28
  private handler;
28
29
  private listening;
29
30
  private listenPromise;
31
+ private logger;
30
32
  private readonly eventQueue;
31
33
  private readonly messageQueue;
32
34
  private readonly pending;
33
35
  private readonly requestTimeoutMs;
34
36
  private readonly responseQueue;
35
37
  private readonly subscribedQueues;
38
+ private logEventHandlerFailure;
39
+ /**
40
+ * Registers the runtime logger that receives inbound event handler failures.
41
+ *
42
+ * @param logger Logger used to report event handler failures.
43
+ */
44
+ setLogger(logger: MicroserviceTransportLogger): void;
36
45
  /**
37
46
  * Creates a RabbitMQ transport with explicit consumer and publisher collaborators.
38
47
  *
@@ -1 +1 @@
1
- {"version":3,"file":"rabbitmq-transport.d.ts","sourceRoot":"","sources":["../../src/transports/rabbitmq-transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE3E,UAAU,oBAAoB;IAC5B,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1F,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAED,UAAU,qBAAqB;IAC7B,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxD;AAWD,mEAAmE;AACnE,MAAM,WAAW,oCAAoC;IACnD,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,qBAAqB,CAAC;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;GAKG;AACH,qBAAa,6BAA8B,YAAW,qBAAqB;IAqB7D,OAAO,CAAC,QAAQ,CAAC,OAAO;IApBpC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAInB;IACL,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IAEtD;;;;OAIG;gBAC0B,OAAO,EAAE,oCAAoC;IAO1E;;;;;OAKG;IACG,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IA4CtD;;;;;;;OAOG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IA6GrF;;;;;;OAMG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAc5D;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YA8Bd,oBAAoB;YAiCpB,aAAa;IAmC3B,OAAO,CAAC,cAAc;IAqBtB,OAAO,CAAC,qBAAqB;CAO9B"}
1
+ {"version":3,"file":"rabbitmq-transport.d.ts","sourceRoot":"","sources":["../../src/transports/rabbitmq-transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,2BAA2B,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGxG,UAAU,oBAAoB;IAC5B,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1F,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAED,UAAU,qBAAqB;IAC7B,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxD;AAWD,mEAAmE;AACnE,MAAM,WAAW,oCAAoC;IACnD,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,qBAAqB,CAAC;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;GAKG;AACH,qBAAa,6BAA8B,YAAW,qBAAqB;IAwC7D,OAAO,CAAC,QAAQ,CAAC,OAAO;IAvCpC,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,MAAM,CAA0C;IACxD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAInB;IACL,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IAEtD,OAAO,CAAC,sBAAsB;IAQ9B;;;;OAIG;IACH,SAAS,CAAC,MAAM,EAAE,2BAA2B,GAAG,IAAI;IAIpD;;;;OAIG;gBAC0B,OAAO,EAAE,oCAAoC;IAO1E;;;;;OAKG;IACG,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAqDtD;;;;;;;OAOG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IA6GrF;;;;;;OAMG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAc5D;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAkDd,oBAAoB;YAuCpB,aAAa;IAsC3B,OAAO,CAAC,cAAc;IAqBtB,OAAO,CAAC,qBAAqB;CAO9B"}
@@ -1,3 +1,5 @@
1
+ import { logTransportEventHandlerFailure } from './event-handler-logger.js';
2
+
1
3
  /** Options for configuring the RabbitMQ microservice transport. */
2
4
 
3
5
  /**
@@ -7,16 +9,34 @@
7
9
  * a queue-oriented topology while still consuming the generic Fluo transport API.
8
10
  */
9
11
  export class RabbitMqMicroserviceTransport {
12
+ closePromise;
10
13
  closing = false;
11
14
  handler;
12
15
  listening = false;
13
16
  listenPromise;
17
+ logger;
14
18
  eventQueue;
15
19
  messageQueue;
16
20
  pending = new Map();
17
21
  requestTimeoutMs;
18
22
  responseQueue;
19
23
  subscribedQueues = new Set();
24
+ logEventHandlerFailure(error) {
25
+ try {
26
+ logTransportEventHandlerFailure(this.logger, 'RabbitMqMicroserviceTransport', error);
27
+ } catch {
28
+ // A failing logger must not mask the event failure the broker still has to observe.
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Registers the runtime logger that receives inbound event handler failures.
34
+ *
35
+ * @param logger Logger used to report event handler failures.
36
+ */
37
+ setLogger(logger) {
38
+ this.logger = logger;
39
+ }
20
40
 
21
41
  /**
22
42
  * Creates a RabbitMQ transport with explicit consumer and publisher collaborators.
@@ -38,7 +58,15 @@ export class RabbitMqMicroserviceTransport {
38
58
  * @returns A promise that resolves once queue consumers are registered.
39
59
  */
40
60
  async listen(handler) {
41
- this.closing = false;
61
+ if (this.closing) {
62
+ if (this.closePromise) {
63
+ throw new Error('RabbitMqMicroserviceTransport is closing. Wait for close() to complete before listen().');
64
+ }
65
+ if (this.subscribedQueues.size > 0) {
66
+ throw new Error('RabbitMQ consumer cleanup is incomplete. Call close() again before listen().');
67
+ }
68
+ this.closing = false;
69
+ }
42
70
  this.handler = handler;
43
71
  if (this.listening) {
44
72
  return;
@@ -51,9 +79,7 @@ export class RabbitMqMicroserviceTransport {
51
79
  const queues = new Set([this.eventQueue, this.messageQueue, this.responseQueue]);
52
80
  try {
53
81
  for (const queue of queues) {
54
- await this.options.consumer.consume(queue, message => {
55
- void this.handleInboundMessage(message).catch(() => undefined);
56
- });
82
+ await this.options.consumer.consume(queue, message => this.handleInboundMessage(message));
57
83
  this.subscribedQueues.add(queue);
58
84
  }
59
85
  } catch (error) {
@@ -200,29 +226,46 @@ export class RabbitMqMicroserviceTransport {
200
226
  * @returns A promise that resolves once shutdown cleanup completes.
201
227
  */
202
228
  async close() {
203
- this.closing = true;
204
- let closeError;
205
- if (this.listenPromise) {
206
- await this.listenPromise;
229
+ if (this.closePromise) {
230
+ await this.closePromise;
231
+ return;
207
232
  }
208
- try {
209
- if (this.listening) {
210
- for (const queue of this.subscribedQueues) {
233
+ this.closing = true;
234
+ this.closePromise = (async () => {
235
+ let closeError;
236
+ let listenError;
237
+ if (this.listenPromise) {
238
+ try {
239
+ await this.listenPromise;
240
+ } catch (error) {
241
+ listenError = error;
242
+ }
243
+ }
244
+ try {
245
+ for (const queue of [...this.subscribedQueues]) {
211
246
  try {
212
247
  await this.options.consumer.cancel(queue);
248
+ this.subscribedQueues.delete(queue);
213
249
  } catch (error) {
214
250
  closeError ??= error;
215
251
  }
216
252
  }
253
+ } finally {
254
+ this.rejectPendingRequests(new Error('RabbitMQ microservice transport closed before response.'));
255
+ this.listening = false;
256
+ this.handler = undefined;
217
257
  }
258
+ if (listenError) {
259
+ throw listenError;
260
+ }
261
+ if (closeError) {
262
+ throw closeError;
263
+ }
264
+ })();
265
+ try {
266
+ await this.closePromise;
218
267
  } finally {
219
- this.subscribedQueues.clear();
220
- this.rejectPendingRequests(new Error('RabbitMQ microservice transport closed before response.'));
221
- this.listening = false;
222
- this.handler = undefined;
223
- }
224
- if (closeError) {
225
- throw closeError;
268
+ this.closePromise = undefined;
226
269
  }
227
270
  }
228
271
  async handleInboundMessage(rawMessage) {
@@ -240,11 +283,16 @@ export class RabbitMqMicroserviceTransport {
240
283
  return;
241
284
  }
242
285
  if (message.kind === 'event') {
243
- await this.handler({
244
- kind: 'event',
245
- pattern: message.pattern,
246
- payload: message.payload
247
- });
286
+ try {
287
+ await this.handler({
288
+ kind: 'event',
289
+ pattern: message.pattern,
290
+ payload: message.payload
291
+ });
292
+ } catch (error) {
293
+ this.logEventHandlerFailure(error);
294
+ throw error;
295
+ }
248
296
  return;
249
297
  }
250
298
  if (message.kind === 'message' && message.requestId) {
@@ -256,19 +304,14 @@ export class RabbitMqMicroserviceTransport {
256
304
  return;
257
305
  }
258
306
  const replyQueue = typeof message.replyTo === 'string' && message.replyTo.length > 0 ? message.replyTo : this.responseQueue;
307
+ let payload;
259
308
  try {
260
- const payload = await this.handler({
309
+ payload = await this.handler({
261
310
  kind: 'message',
262
311
  pattern: message.pattern,
263
312
  payload: message.payload,
264
313
  requestId: message.requestId
265
314
  });
266
- await this.options.publisher.publish(replyQueue, JSON.stringify({
267
- kind: 'response',
268
- pattern: message.pattern,
269
- payload,
270
- requestId: message.requestId
271
- }));
272
315
  } catch (error) {
273
316
  const errorMessage = error instanceof Error ? error.message : 'Unhandled microservice error';
274
317
  await this.options.publisher.publish(replyQueue, JSON.stringify({
@@ -277,7 +320,14 @@ export class RabbitMqMicroserviceTransport {
277
320
  pattern: message.pattern,
278
321
  requestId: message.requestId
279
322
  }));
323
+ return;
280
324
  }
325
+ await this.options.publisher.publish(replyQueue, JSON.stringify({
326
+ kind: 'response',
327
+ pattern: message.pattern,
328
+ payload,
329
+ requestId: message.requestId
330
+ }));
281
331
  }
282
332
  handleResponse(message) {
283
333
  if (!message.requestId) {
@@ -15,6 +15,12 @@ export interface RedisStreamClientLike {
15
15
  blockMs?: number;
16
16
  count?: number;
17
17
  }): Promise<readonly StreamReadGroupResult[] | null>;
18
+ xautoclaim?(stream: string, group: string, consumer: string, minIdleTimeMs: number, startId: string, options?: {
19
+ count?: number;
20
+ }): Promise<{
21
+ readonly entries: readonly StreamReadGroupResult[];
22
+ readonly nextStartId: string;
23
+ }>;
18
24
  xack(stream: string, group: string, id: string): Promise<void>;
19
25
  get?(key: string): Promise<string | null>;
20
26
  incr?(key: string): Promise<number>;
@@ -45,6 +51,14 @@ export interface RedisStreamsMicroserviceTransportOptions {
45
51
  responseRetentionMaxLen?: number;
46
52
  consumerGroup?: string;
47
53
  namespace?: string;
54
+ /**
55
+ * Minimum pending-entry idle time before `XAUTOCLAIM` recovery in the shared request group
56
+ * or this listener's instance-scoped event group.
57
+ *
58
+ * Defaults to `60_000`; set a non-positive value to disable recovery. The reader client must
59
+ * implement {@link RedisStreamClientLike.xautoclaim} for recovery to run.
60
+ */
61
+ pendingReclaimIdleMs?: number;
48
62
  requestTimeoutMs?: number;
49
63
  pollBlockMs?: number;
50
64
  }
@@ -66,9 +80,12 @@ export declare class RedisStreamsMicroserviceTransport implements MicroserviceTr
66
80
  private messageGroupLeaseRegistered;
67
81
  private ownsMessageGroup;
68
82
  private readonly pending;
83
+ private readonly pendingReclaimFailureGroups;
84
+ private readonly pendingReclaimStartIds;
69
85
  private pollPromises;
70
86
  private readonly namespace;
71
87
  private readonly consumerGroup;
88
+ private readonly pendingReclaimIdleMs;
72
89
  private readonly requestTimeoutMs;
73
90
  private readonly pollBlockMs;
74
91
  private readonly messageRetentionMaxLen;
@@ -115,6 +132,7 @@ export declare class RedisStreamsMicroserviceTransport implements MicroserviceTr
115
132
  private registerMessageGroupLease;
116
133
  private releaseMessageGroupLease;
117
134
  private pollStream;
135
+ private reclaimPendingEntries;
118
136
  private handleStreamEntry;
119
137
  private handleInboundRequest;
120
138
  private publishFrame;
@@ -1 +1 @@
1
- {"version":3,"file":"redis-streams-transport.d.ts","sourceRoot":"","sources":["../../src/transports/redis-streams-transport.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"redis-streams-transport.d.ts","sourceRoot":"","sources":["../../src/transports/redis-streams-transport.ts"],"names":[],"mappings":"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"}