@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.
- package/README.ko.md +64 -6
- package/README.md +64 -6
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +2 -1
- package/dist/service.d.ts +15 -5
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +96 -38
- package/dist/status.d.ts +3 -0
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +10 -2
- package/dist/transports/grpc-transport.d.ts +4 -2
- package/dist/transports/grpc-transport.d.ts.map +1 -1
- package/dist/transports/grpc-transport.js +241 -241
- package/dist/transports/kafka-transport.d.ts +9 -1
- package/dist/transports/kafka-transport.d.ts.map +1 -1
- package/dist/transports/kafka-transport.js +41 -21
- package/dist/transports/mqtt-transport.d.ts +1 -0
- package/dist/transports/mqtt-transport.d.ts.map +1 -1
- package/dist/transports/mqtt-transport.js +22 -1
- package/dist/transports/nats-transport.d.ts +3 -0
- package/dist/transports/nats-transport.d.ts.map +1 -1
- package/dist/transports/nats-transport.js +83 -30
- package/dist/transports/rabbitmq-transport.d.ts +10 -1
- package/dist/transports/rabbitmq-transport.d.ts.map +1 -1
- package/dist/transports/rabbitmq-transport.js +80 -30
- package/dist/transports/redis-streams-transport.d.ts +18 -0
- package/dist/transports/redis-streams-transport.d.ts.map +1 -1
- package/dist/transports/redis-streams-transport.js +46 -3
- package/dist/transports/redis-transport.d.ts +1 -1
- package/dist/transports/redis-transport.d.ts.map +1 -1
- package/dist/transports/redis-transport.js +32 -16
- package/dist/transports/tcp-transport.d.ts +1 -0
- package/dist/transports/tcp-transport.d.ts.map +1 -1
- package/dist/transports/tcp-transport.js +45 -44
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- 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
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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;
|
|
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
|
|
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
|
-
|
|
58
|
-
this.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
178
|
-
|
|
219
|
+
this.closePromise = (async () => {
|
|
220
|
+
const cleanupErrors = [];
|
|
221
|
+
const retainedSubscriptions = [];
|
|
179
222
|
for (const subscription of this.subscriptions) {
|
|
180
|
-
|
|
223
|
+
try {
|
|
224
|
+
subscription.unsubscribe();
|
|
225
|
+
} catch (error) {
|
|
226
|
+
cleanupErrors.push(error);
|
|
227
|
+
retainedSubscriptions.push(subscription);
|
|
228
|
+
}
|
|
181
229
|
}
|
|
182
|
-
|
|
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
|
-
|
|
193
|
-
|
|
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
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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;
|
|
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
|
|
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.
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
await this.listenPromise;
|
|
229
|
+
if (this.closePromise) {
|
|
230
|
+
await this.closePromise;
|
|
231
|
+
return;
|
|
207
232
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
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.
|
|
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
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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
|
-
|
|
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":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,2BAA2B,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGxG,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACnD;AAED,wEAAwE;AACxE,MAAM,WAAW,uBAAuB;IACtC,8EAA8E;IAC9E,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACrC;AAED,mGAAmG;AACnG,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACzG,UAAU,CACR,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAC7C,OAAO,CAAC,SAAS,qBAAqB,EAAE,GAAG,IAAI,CAAC,CAAC;IACpD,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1C,IAAI,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,IAAI,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/F,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7D;AAED,wEAAwE;AACxE,MAAM,WAAW,wCAAwC;IACvD,YAAY,EAAE,qBAAqB,CAAC;IACpC,YAAY,EAAE,qBAAqB,CAAC;IACpC;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oFAAoF;IACpF,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAsBD;;;;;GAKG;AACH,qBAAa,iCAAkC,YAAW,qBAAqB;
|
|
1
|
+
{"version":3,"file":"redis-streams-transport.d.ts","sourceRoot":"","sources":["../../src/transports/redis-streams-transport.ts"],"names":[],"mappings":"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"}
|