@fluojs/microservices 1.0.3 → 1.0.5
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 +50 -4
- package/README.md +50 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/module.js +1 -1
- package/dist/service.d.ts +3 -2
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +7 -4
- package/dist/status.d.ts +2 -0
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +5 -3
- package/dist/transports/grpc-transport.d.ts +4 -0
- package/dist/transports/grpc-transport.d.ts.map +1 -1
- package/dist/transports/grpc-transport.js +226 -260
- package/dist/transports/kafka-transport.d.ts +1 -0
- package/dist/transports/kafka-transport.d.ts.map +1 -1
- package/dist/transports/kafka-transport.js +56 -36
- package/dist/transports/mqtt-transport.d.ts +4 -0
- package/dist/transports/mqtt-transport.d.ts.map +1 -1
- package/dist/transports/mqtt-transport.js +91 -32
- package/dist/transports/nats-transport.d.ts +1 -0
- package/dist/transports/nats-transport.d.ts.map +1 -1
- package/dist/transports/nats-transport.js +53 -23
- package/dist/transports/rabbitmq-transport.d.ts +1 -0
- package/dist/transports/rabbitmq-transport.d.ts.map +1 -1
- package/dist/transports/rabbitmq-transport.js +54 -29
- package/dist/transports/redis-streams-transport.d.ts.map +1 -1
- package/dist/transports/redis-streams-transport.js +22 -2
- package/dist/transports/tcp-transport.d.ts +8 -2
- package/dist/transports/tcp-transport.d.ts.map +1 -1
- package/dist/transports/tcp-transport.js +4 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* replies without leaking cross-request state through the shared producer/consumer pair.
|
|
8
8
|
*/
|
|
9
9
|
export class KafkaMicroserviceTransport {
|
|
10
|
+
closePromise;
|
|
10
11
|
closing = false;
|
|
11
12
|
handler;
|
|
12
13
|
listening = false;
|
|
@@ -37,7 +38,12 @@ export class KafkaMicroserviceTransport {
|
|
|
37
38
|
* @returns A promise that resolves once all subscriptions are active.
|
|
38
39
|
*/
|
|
39
40
|
async listen(handler) {
|
|
40
|
-
this.closing
|
|
41
|
+
if (this.closing) {
|
|
42
|
+
if (this.closePromise) {
|
|
43
|
+
throw new Error('KafkaMicroserviceTransport is closing. Wait for close() to complete before listen().');
|
|
44
|
+
}
|
|
45
|
+
this.closing = false;
|
|
46
|
+
}
|
|
41
47
|
this.handler = handler;
|
|
42
48
|
if (this.listening) {
|
|
43
49
|
return;
|
|
@@ -49,17 +55,11 @@ export class KafkaMicroserviceTransport {
|
|
|
49
55
|
this.listenPromise = (async () => {
|
|
50
56
|
const subscribed = [];
|
|
51
57
|
try {
|
|
52
|
-
await this.options.consumer.subscribe(this.eventTopic, message =>
|
|
53
|
-
void this.handleInboundEvent(message).catch(() => undefined);
|
|
54
|
-
});
|
|
58
|
+
await this.options.consumer.subscribe(this.eventTopic, message => this.handleInboundEvent(message));
|
|
55
59
|
subscribed.push(this.eventTopic);
|
|
56
|
-
await this.options.consumer.subscribe(this.messageTopic, message =>
|
|
57
|
-
void this.handleInboundRequest(message).catch(() => undefined);
|
|
58
|
-
});
|
|
60
|
+
await this.options.consumer.subscribe(this.messageTopic, message => this.handleInboundRequest(message));
|
|
59
61
|
subscribed.push(this.messageTopic);
|
|
60
|
-
await this.options.consumer.subscribe(this.responseTopic, message =>
|
|
61
|
-
void this.handleInboundResponse(message).catch(() => undefined);
|
|
62
|
-
});
|
|
62
|
+
await this.options.consumer.subscribe(this.responseTopic, message => this.handleInboundResponse(message));
|
|
63
63
|
subscribed.push(this.responseTopic);
|
|
64
64
|
} catch (error) {
|
|
65
65
|
for (const topic of subscribed) {
|
|
@@ -138,6 +138,13 @@ export class KafkaMicroserviceTransport {
|
|
|
138
138
|
});
|
|
139
139
|
}
|
|
140
140
|
void Promise.resolve().then(async () => {
|
|
141
|
+
if (!this.pending.has(requestId)) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (signal?.aborted) {
|
|
145
|
+
entry.reject(new Error('Kafka request aborted before publish.'));
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
141
148
|
if (this.closing) {
|
|
142
149
|
entry.reject(new Error('Kafka microservice transport closed before request dispatch.'));
|
|
143
150
|
return;
|
|
@@ -174,30 +181,41 @@ export class KafkaMicroserviceTransport {
|
|
|
174
181
|
* @returns A promise that resolves once shutdown cleanup completes.
|
|
175
182
|
*/
|
|
176
183
|
async close() {
|
|
177
|
-
this.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
await this.listenPromise;
|
|
184
|
+
if (this.closePromise) {
|
|
185
|
+
await this.closePromise;
|
|
186
|
+
return;
|
|
181
187
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
188
|
+
this.closing = true;
|
|
189
|
+
this.closePromise = (async () => {
|
|
190
|
+
let closeError;
|
|
191
|
+
if (this.listenPromise) {
|
|
192
|
+
await this.listenPromise;
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
if (this.listening) {
|
|
196
|
+
for (const topic of new Set([this.eventTopic, this.messageTopic, this.responseTopic])) {
|
|
197
|
+
try {
|
|
198
|
+
await this.options.consumer.unsubscribe(topic);
|
|
199
|
+
} catch (error) {
|
|
200
|
+
closeError ??= error;
|
|
201
|
+
}
|
|
189
202
|
}
|
|
190
203
|
}
|
|
204
|
+
} finally {
|
|
205
|
+
this.handler = undefined;
|
|
206
|
+
this.listening = false;
|
|
207
|
+
for (const pending of [...this.pending.values()]) {
|
|
208
|
+
pending.reject(new Error('Kafka microservice transport closed before response.'));
|
|
209
|
+
}
|
|
191
210
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
this.listening = false;
|
|
195
|
-
for (const pending of [...this.pending.values()]) {
|
|
196
|
-
pending.reject(new Error('Kafka microservice transport closed before response.'));
|
|
211
|
+
if (closeError) {
|
|
212
|
+
throw closeError;
|
|
197
213
|
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
|
|
214
|
+
})();
|
|
215
|
+
try {
|
|
216
|
+
await this.closePromise;
|
|
217
|
+
} finally {
|
|
218
|
+
this.closePromise = undefined;
|
|
201
219
|
}
|
|
202
220
|
}
|
|
203
221
|
async handleInboundEvent(rawMessage) {
|
|
@@ -223,19 +241,14 @@ export class KafkaMicroserviceTransport {
|
|
|
223
241
|
return;
|
|
224
242
|
}
|
|
225
243
|
const replyTopic = message.replyTopic && message.replyTopic.length > 0 ? message.replyTopic : this.responseTopic;
|
|
244
|
+
let payload;
|
|
226
245
|
try {
|
|
227
|
-
|
|
246
|
+
payload = await this.handler({
|
|
228
247
|
kind: 'message',
|
|
229
248
|
pattern: message.pattern,
|
|
230
249
|
payload: message.payload,
|
|
231
250
|
requestId: message.requestId
|
|
232
251
|
});
|
|
233
|
-
await this.options.producer.publish(replyTopic, JSON.stringify({
|
|
234
|
-
kind: 'response',
|
|
235
|
-
pattern: message.pattern,
|
|
236
|
-
payload,
|
|
237
|
-
requestId: message.requestId
|
|
238
|
-
}));
|
|
239
252
|
} catch (error) {
|
|
240
253
|
const errorMessage = error instanceof Error ? error.message : 'Unhandled microservice error';
|
|
241
254
|
await this.options.producer.publish(replyTopic, JSON.stringify({
|
|
@@ -244,7 +257,14 @@ export class KafkaMicroserviceTransport {
|
|
|
244
257
|
pattern: message.pattern,
|
|
245
258
|
requestId: message.requestId
|
|
246
259
|
}));
|
|
260
|
+
return;
|
|
247
261
|
}
|
|
262
|
+
await this.options.producer.publish(replyTopic, JSON.stringify({
|
|
263
|
+
kind: 'response',
|
|
264
|
+
pattern: message.pattern,
|
|
265
|
+
payload,
|
|
266
|
+
requestId: message.requestId
|
|
267
|
+
}));
|
|
248
268
|
}
|
|
249
269
|
async handleInboundResponse(rawMessage) {
|
|
250
270
|
const message = this.parseMessage(rawMessage);
|
|
@@ -53,9 +53,12 @@ export interface MqttMicroserviceTransportOptions {
|
|
|
53
53
|
export declare class MqttMicroserviceTransport implements MicroserviceTransport {
|
|
54
54
|
private readonly options;
|
|
55
55
|
private client;
|
|
56
|
+
private closePromise;
|
|
56
57
|
private closing;
|
|
57
58
|
private handler;
|
|
58
59
|
private readonly internallyOwnedClient;
|
|
60
|
+
/** Indicates whether MQTT owns the client instance it resolves and closes. */
|
|
61
|
+
readonly ownsResources: boolean;
|
|
59
62
|
private logger;
|
|
60
63
|
private listening;
|
|
61
64
|
private listenPromise;
|
|
@@ -118,6 +121,7 @@ export declare class MqttMicroserviceTransport implements MicroserviceTransport
|
|
|
118
121
|
private subscribeTopic;
|
|
119
122
|
private unsubscribeTopic;
|
|
120
123
|
private endClient;
|
|
124
|
+
private disposeOwnedClientAfterListenFailure;
|
|
121
125
|
private logEventHandlerFailure;
|
|
122
126
|
}
|
|
123
127
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mqtt-transport.d.ts","sourceRoot":"","sources":["../../src/transports/mqtt-transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,2BAA2B,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGxG,KAAK,aAAa,GAAG,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE7D,UAAU,kBAAkB;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,UAAU,oBAAoB;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,UAAU,kBAAkB;IAC1B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,UAAU,cAAc;IACtB,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;IAC/D,GAAG,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,KAAK,IAAI,GAAG,IAAI,CAAC;IACzG,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,KAAK,IAAI,GAAG,IAAI,CAAC;IACvG,OAAO,CACL,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,GACjC,IAAI,CAAC;IACR,SAAS,CACP,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,oBAAoB,EAC7B,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,GACjC,IAAI,CAAC;IACR,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;CACtE;AAED,UAAU,cAAc;IACtB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,cAAc,CAAC;CACpE;AAsBD,+DAA+D;AAC/D,MAAM,WAAW,gCAAgC;IAC/C,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACrB,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACvB,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B;AAED;;;;;GAKG;AACH,qBAAa,yBAA0B,YAAW,qBAAqB;
|
|
1
|
+
{"version":3,"file":"mqtt-transport.d.ts","sourceRoot":"","sources":["../../src/transports/mqtt-transport.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,9 +15,12 @@ const mqttKinds = {
|
|
|
15
15
|
*/
|
|
16
16
|
export class MqttMicroserviceTransport {
|
|
17
17
|
client;
|
|
18
|
+
closePromise;
|
|
18
19
|
closing = false;
|
|
19
20
|
handler;
|
|
20
21
|
internallyOwnedClient;
|
|
22
|
+
/** Indicates whether MQTT owns the client instance it resolves and closes. */
|
|
23
|
+
ownsResources;
|
|
21
24
|
logger;
|
|
22
25
|
listening = false;
|
|
23
26
|
listenPromise;
|
|
@@ -56,6 +59,7 @@ export class MqttMicroserviceTransport {
|
|
|
56
59
|
this.requestTimeoutMs = options.requestTimeoutMs ?? 3_000;
|
|
57
60
|
this.client = options.client;
|
|
58
61
|
this.internallyOwnedClient = !options.client;
|
|
62
|
+
this.ownsResources = this.internallyOwnedClient;
|
|
59
63
|
}
|
|
60
64
|
setLogger(logger) {
|
|
61
65
|
this.logger = logger;
|
|
@@ -68,7 +72,12 @@ export class MqttMicroserviceTransport {
|
|
|
68
72
|
* @returns A promise that resolves once all subscriptions are active.
|
|
69
73
|
*/
|
|
70
74
|
async listen(handler) {
|
|
71
|
-
this.closing
|
|
75
|
+
if (this.closing) {
|
|
76
|
+
if (this.closePromise) {
|
|
77
|
+
throw new Error('MqttMicroserviceTransport is closing. Wait for close() to complete before listen().');
|
|
78
|
+
}
|
|
79
|
+
this.closing = false;
|
|
80
|
+
}
|
|
72
81
|
this.handler = handler;
|
|
73
82
|
if (this.listening) {
|
|
74
83
|
return;
|
|
@@ -93,6 +102,9 @@ export class MqttMicroserviceTransport {
|
|
|
93
102
|
await this.unsubscribeTopic(client, topic).catch(() => undefined);
|
|
94
103
|
}
|
|
95
104
|
client.off?.('message', this.messageListener);
|
|
105
|
+
this.handler = undefined;
|
|
106
|
+
this.listening = false;
|
|
107
|
+
await this.disposeOwnedClientAfterListenFailure(client);
|
|
96
108
|
throw error;
|
|
97
109
|
}
|
|
98
110
|
this.listening = true;
|
|
@@ -175,11 +187,29 @@ export class MqttMicroserviceTransport {
|
|
|
175
187
|
});
|
|
176
188
|
}
|
|
177
189
|
void Promise.resolve().then(async () => {
|
|
190
|
+
if (!this.pending.has(requestId)) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (signal?.aborted) {
|
|
194
|
+
entry.reject(new Error('MQTT request aborted before publish.'));
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
178
197
|
if (this.closing) {
|
|
179
198
|
entry.reject(new Error('MQTT microservice transport closed before response.'));
|
|
180
199
|
return;
|
|
181
200
|
}
|
|
182
201
|
const client = await this.resolveClient();
|
|
202
|
+
if (!this.pending.has(requestId)) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (signal?.aborted) {
|
|
206
|
+
entry.reject(new Error('MQTT request aborted before publish.'));
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (this.closing) {
|
|
210
|
+
entry.reject(new Error('MQTT microservice transport closed before response.'));
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
183
213
|
await this.publish(client, this.messageTopic, frame, {
|
|
184
214
|
qos: this.messageQos,
|
|
185
215
|
retain: this.messageRetain
|
|
@@ -219,44 +249,59 @@ export class MqttMicroserviceTransport {
|
|
|
219
249
|
* @returns A promise that resolves once shutdown cleanup completes.
|
|
220
250
|
*/
|
|
221
251
|
async close() {
|
|
222
|
-
this.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
await this.listenPromise;
|
|
252
|
+
if (this.closePromise) {
|
|
253
|
+
await this.closePromise;
|
|
254
|
+
return;
|
|
226
255
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
256
|
+
this.closing = true;
|
|
257
|
+
this.closePromise = (async () => {
|
|
258
|
+
let closeError;
|
|
259
|
+
if (this.listenPromise) {
|
|
260
|
+
try {
|
|
261
|
+
await this.listenPromise;
|
|
262
|
+
} catch (error) {
|
|
263
|
+
closeError = error;
|
|
236
264
|
}
|
|
237
265
|
}
|
|
238
|
-
|
|
239
|
-
client
|
|
240
|
-
if (this.
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
266
|
+
try {
|
|
267
|
+
const client = this.client;
|
|
268
|
+
if (client && this.listening) {
|
|
269
|
+
for (const topic of [this.eventTopic, this.messageTopic, this.replyTopic]) {
|
|
270
|
+
try {
|
|
271
|
+
await this.unsubscribeTopic(client, topic);
|
|
272
|
+
} catch (error) {
|
|
273
|
+
closeError ??= error;
|
|
274
|
+
}
|
|
245
275
|
}
|
|
246
276
|
}
|
|
277
|
+
if (client) {
|
|
278
|
+
client.off?.('message', this.messageListener);
|
|
279
|
+
if (this.internallyOwnedClient) {
|
|
280
|
+
try {
|
|
281
|
+
await this.endClient(client);
|
|
282
|
+
} catch (error) {
|
|
283
|
+
closeError ??= error;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
} finally {
|
|
288
|
+
this.handler = undefined;
|
|
289
|
+
this.listening = false;
|
|
290
|
+
if (this.internallyOwnedClient) {
|
|
291
|
+
this.client = undefined;
|
|
292
|
+
}
|
|
293
|
+
for (const pending of [...this.pending.values()]) {
|
|
294
|
+
pending.reject(new Error('MQTT microservice transport closed before response.'));
|
|
295
|
+
}
|
|
247
296
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
this.listening = false;
|
|
251
|
-
if (this.internallyOwnedClient) {
|
|
252
|
-
this.client = undefined;
|
|
253
|
-
}
|
|
254
|
-
for (const pending of [...this.pending.values()]) {
|
|
255
|
-
pending.reject(new Error('MQTT microservice transport closed before response.'));
|
|
297
|
+
if (closeError) {
|
|
298
|
+
throw closeError;
|
|
256
299
|
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
|
|
300
|
+
})();
|
|
301
|
+
try {
|
|
302
|
+
await this.closePromise;
|
|
303
|
+
} finally {
|
|
304
|
+
this.closePromise = undefined;
|
|
260
305
|
}
|
|
261
306
|
}
|
|
262
307
|
async handleInbound(topic, rawMessage) {
|
|
@@ -419,6 +464,20 @@ export class MqttMicroserviceTransport {
|
|
|
419
464
|
});
|
|
420
465
|
});
|
|
421
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
|
+
}
|
|
422
481
|
logEventHandlerFailure(error) {
|
|
423
482
|
logTransportEventHandlerFailure(this.logger, 'MqttMicroserviceTransport', error);
|
|
424
483
|
}
|
|
@@ -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;IA2BzD,OAAO,CAAC,QAAQ,CAAC,OAAO;IA1BpC,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;;;;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;IAwCtD;;;;;;;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;YAuCd,kBAAkB;YAsBlB,oBAAoB;IAwBlC,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;
|
|
@@ -49,18 +50,36 @@ export class NatsMicroserviceTransport {
|
|
|
49
50
|
* @returns A promise that resolves once subscriptions are active.
|
|
50
51
|
*/
|
|
51
52
|
async listen(handler) {
|
|
52
|
-
this.closing
|
|
53
|
+
if (this.closing) {
|
|
54
|
+
if (this.closePromise) {
|
|
55
|
+
throw new Error('NATS microservice transport is closing. Wait for close() to complete before listen().');
|
|
56
|
+
}
|
|
57
|
+
this.closing = false;
|
|
58
|
+
}
|
|
53
59
|
this.handler = handler;
|
|
54
60
|
if (this.listening) {
|
|
55
61
|
return;
|
|
56
62
|
}
|
|
57
|
-
|
|
58
|
-
this.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
try {
|
|
64
|
+
this.subscriptions.push(this.options.client.subscribe(this.eventSubject, message => {
|
|
65
|
+
this.handleEventMessageSafely(message);
|
|
66
|
+
}));
|
|
67
|
+
this.subscriptions.push(this.options.client.subscribe(this.messageSubject, message => {
|
|
68
|
+
void this.handleRequestMessage(message);
|
|
69
|
+
}));
|
|
70
|
+
} catch (error) {
|
|
71
|
+
for (const subscription of this.subscriptions.reverse()) {
|
|
72
|
+
try {
|
|
73
|
+
subscription.unsubscribe();
|
|
74
|
+
} catch {
|
|
75
|
+
// Preserve the original subscription failure; partial setup cleanup is best-effort.
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
this.subscriptions = [];
|
|
79
|
+
this.handler = undefined;
|
|
80
|
+
this.listening = false;
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
64
83
|
this.listening = true;
|
|
65
84
|
}
|
|
66
85
|
|
|
@@ -173,24 +192,35 @@ export class NatsMicroserviceTransport {
|
|
|
173
192
|
* @returns A promise that resolves once shutdown cleanup completes.
|
|
174
193
|
*/
|
|
175
194
|
async close() {
|
|
195
|
+
if (this.closePromise) {
|
|
196
|
+
await this.closePromise;
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
176
199
|
this.closing = true;
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
subscription.
|
|
200
|
+
this.closePromise = (async () => {
|
|
201
|
+
let closeError;
|
|
202
|
+
try {
|
|
203
|
+
for (const subscription of this.subscriptions) {
|
|
204
|
+
subscription.unsubscribe();
|
|
205
|
+
}
|
|
206
|
+
} catch (error) {
|
|
207
|
+
closeError = error;
|
|
208
|
+
} finally {
|
|
209
|
+
this.subscriptions = [];
|
|
210
|
+
this.listening = false;
|
|
211
|
+
this.handler = undefined;
|
|
212
|
+
for (const pending of [...this.pending.values()]) {
|
|
213
|
+
pending.reject(new Error('NATS microservice transport closed before response.'));
|
|
214
|
+
}
|
|
181
215
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
} finally {
|
|
185
|
-
this.subscriptions = [];
|
|
186
|
-
this.listening = false;
|
|
187
|
-
this.handler = undefined;
|
|
188
|
-
for (const pending of [...this.pending.values()]) {
|
|
189
|
-
pending.reject(new Error('NATS microservice transport closed before response.'));
|
|
216
|
+
if (closeError) {
|
|
217
|
+
throw closeError;
|
|
190
218
|
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
|
|
219
|
+
})();
|
|
220
|
+
try {
|
|
221
|
+
await this.closePromise;
|
|
222
|
+
} finally {
|
|
223
|
+
this.closePromise = undefined;
|
|
194
224
|
}
|
|
195
225
|
}
|
|
196
226
|
async handleEventMessage(message) {
|
|
@@ -23,6 +23,7 @@ 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;
|
|
@@ -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;
|
|
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;IAsB7D,OAAO,CAAC,QAAQ,CAAC,OAAO;IArBpC,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,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;IAiDtD;;;;;;;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;YAoDd,oBAAoB;YAiCpB,aAAa;IAsC3B,OAAO,CAAC,cAAc;IAqBtB,OAAO,CAAC,qBAAqB;CAO9B"}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* a queue-oriented topology while still consuming the generic Fluo transport API.
|
|
8
8
|
*/
|
|
9
9
|
export class RabbitMqMicroserviceTransport {
|
|
10
|
+
closePromise;
|
|
10
11
|
closing = false;
|
|
11
12
|
handler;
|
|
12
13
|
listening = false;
|
|
@@ -38,7 +39,12 @@ export class RabbitMqMicroserviceTransport {
|
|
|
38
39
|
* @returns A promise that resolves once queue consumers are registered.
|
|
39
40
|
*/
|
|
40
41
|
async listen(handler) {
|
|
41
|
-
this.closing
|
|
42
|
+
if (this.closing) {
|
|
43
|
+
if (this.closePromise) {
|
|
44
|
+
throw new Error('RabbitMqMicroserviceTransport is closing. Wait for close() to complete before listen().');
|
|
45
|
+
}
|
|
46
|
+
this.closing = false;
|
|
47
|
+
}
|
|
42
48
|
this.handler = handler;
|
|
43
49
|
if (this.listening) {
|
|
44
50
|
return;
|
|
@@ -51,9 +57,7 @@ export class RabbitMqMicroserviceTransport {
|
|
|
51
57
|
const queues = new Set([this.eventQueue, this.messageQueue, this.responseQueue]);
|
|
52
58
|
try {
|
|
53
59
|
for (const queue of queues) {
|
|
54
|
-
await this.options.consumer.consume(queue, message =>
|
|
55
|
-
void this.handleInboundMessage(message).catch(() => undefined);
|
|
56
|
-
});
|
|
60
|
+
await this.options.consumer.consume(queue, message => this.handleInboundMessage(message));
|
|
57
61
|
this.subscribedQueues.add(queue);
|
|
58
62
|
}
|
|
59
63
|
} catch (error) {
|
|
@@ -200,29 +204,48 @@ export class RabbitMqMicroserviceTransport {
|
|
|
200
204
|
* @returns A promise that resolves once shutdown cleanup completes.
|
|
201
205
|
*/
|
|
202
206
|
async close() {
|
|
203
|
-
this.
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
await this.listenPromise;
|
|
207
|
+
if (this.closePromise) {
|
|
208
|
+
await this.closePromise;
|
|
209
|
+
return;
|
|
207
210
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
211
|
+
this.closing = true;
|
|
212
|
+
this.closePromise = (async () => {
|
|
213
|
+
let closeError;
|
|
214
|
+
let listenError;
|
|
215
|
+
if (this.listenPromise) {
|
|
216
|
+
try {
|
|
217
|
+
await this.listenPromise;
|
|
218
|
+
} catch (error) {
|
|
219
|
+
listenError = error;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
try {
|
|
223
|
+
if (this.listening) {
|
|
224
|
+
for (const queue of this.subscribedQueues) {
|
|
225
|
+
try {
|
|
226
|
+
await this.options.consumer.cancel(queue);
|
|
227
|
+
} catch (error) {
|
|
228
|
+
closeError ??= error;
|
|
229
|
+
}
|
|
215
230
|
}
|
|
216
231
|
}
|
|
232
|
+
} finally {
|
|
233
|
+
this.subscribedQueues.clear();
|
|
234
|
+
this.rejectPendingRequests(new Error('RabbitMQ microservice transport closed before response.'));
|
|
235
|
+
this.listening = false;
|
|
236
|
+
this.handler = undefined;
|
|
237
|
+
}
|
|
238
|
+
if (listenError) {
|
|
239
|
+
throw listenError;
|
|
217
240
|
}
|
|
241
|
+
if (closeError) {
|
|
242
|
+
throw closeError;
|
|
243
|
+
}
|
|
244
|
+
})();
|
|
245
|
+
try {
|
|
246
|
+
await this.closePromise;
|
|
218
247
|
} 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;
|
|
248
|
+
this.closePromise = undefined;
|
|
226
249
|
}
|
|
227
250
|
}
|
|
228
251
|
async handleInboundMessage(rawMessage) {
|
|
@@ -256,19 +279,14 @@ export class RabbitMqMicroserviceTransport {
|
|
|
256
279
|
return;
|
|
257
280
|
}
|
|
258
281
|
const replyQueue = typeof message.replyTo === 'string' && message.replyTo.length > 0 ? message.replyTo : this.responseQueue;
|
|
282
|
+
let payload;
|
|
259
283
|
try {
|
|
260
|
-
|
|
284
|
+
payload = await this.handler({
|
|
261
285
|
kind: 'message',
|
|
262
286
|
pattern: message.pattern,
|
|
263
287
|
payload: message.payload,
|
|
264
288
|
requestId: message.requestId
|
|
265
289
|
});
|
|
266
|
-
await this.options.publisher.publish(replyQueue, JSON.stringify({
|
|
267
|
-
kind: 'response',
|
|
268
|
-
pattern: message.pattern,
|
|
269
|
-
payload,
|
|
270
|
-
requestId: message.requestId
|
|
271
|
-
}));
|
|
272
290
|
} catch (error) {
|
|
273
291
|
const errorMessage = error instanceof Error ? error.message : 'Unhandled microservice error';
|
|
274
292
|
await this.options.publisher.publish(replyQueue, JSON.stringify({
|
|
@@ -277,7 +295,14 @@ export class RabbitMqMicroserviceTransport {
|
|
|
277
295
|
pattern: message.pattern,
|
|
278
296
|
requestId: message.requestId
|
|
279
297
|
}));
|
|
298
|
+
return;
|
|
280
299
|
}
|
|
300
|
+
await this.options.publisher.publish(replyQueue, JSON.stringify({
|
|
301
|
+
kind: 'response',
|
|
302
|
+
pattern: message.pattern,
|
|
303
|
+
payload,
|
|
304
|
+
requestId: message.requestId
|
|
305
|
+
}));
|
|
281
306
|
}
|
|
282
307
|
handleResponse(message) {
|
|
283
308
|
if (!message.requestId) {
|