@horizon-republic/nestjs-jetstream 2.3.0 → 2.3.4
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.md +110 -99
- package/dist/index.cjs +164 -93
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +148 -39
- package/dist/index.d.ts +148 -39
- package/dist/index.js +167 -93
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.cjs
CHANGED
|
@@ -203,7 +203,11 @@ var JetstreamRecordBuilder = class {
|
|
|
203
203
|
constructor(data) {
|
|
204
204
|
this.data = data;
|
|
205
205
|
}
|
|
206
|
-
/**
|
|
206
|
+
/**
|
|
207
|
+
* Set the message payload.
|
|
208
|
+
*
|
|
209
|
+
* @param data - Payload to serialize via the configured {@link Codec}.
|
|
210
|
+
*/
|
|
207
211
|
setData(data) {
|
|
208
212
|
this.data = data;
|
|
209
213
|
return this;
|
|
@@ -211,6 +215,8 @@ var JetstreamRecordBuilder = class {
|
|
|
211
215
|
/**
|
|
212
216
|
* Set a single custom header.
|
|
213
217
|
*
|
|
218
|
+
* @param key - Header name (e.g. `'x-tenant'`).
|
|
219
|
+
* @param value - Header value.
|
|
214
220
|
* @throws Error if the header name is reserved by the transport.
|
|
215
221
|
*/
|
|
216
222
|
setHeader(key, value) {
|
|
@@ -221,6 +227,7 @@ var JetstreamRecordBuilder = class {
|
|
|
221
227
|
/**
|
|
222
228
|
* Set multiple custom headers at once.
|
|
223
229
|
*
|
|
230
|
+
* @param headers - Key-value pairs to set as headers.
|
|
224
231
|
* @throws Error if any header name is reserved by the transport.
|
|
225
232
|
*/
|
|
226
233
|
setHeaders(headers2) {
|
|
@@ -229,12 +236,20 @@ var JetstreamRecordBuilder = class {
|
|
|
229
236
|
}
|
|
230
237
|
return this;
|
|
231
238
|
}
|
|
232
|
-
/**
|
|
239
|
+
/**
|
|
240
|
+
* Set per-request RPC timeout.
|
|
241
|
+
*
|
|
242
|
+
* @param ms - Timeout in milliseconds. Overrides the global RPC timeout for this request only.
|
|
243
|
+
*/
|
|
233
244
|
setTimeout(ms) {
|
|
234
245
|
this.timeout = ms;
|
|
235
246
|
return this;
|
|
236
247
|
}
|
|
237
|
-
/**
|
|
248
|
+
/**
|
|
249
|
+
* Build the immutable {@link JetstreamRecord}.
|
|
250
|
+
*
|
|
251
|
+
* @returns A frozen record ready to pass to `client.send()` or `client.emit()`.
|
|
252
|
+
*/
|
|
238
253
|
build() {
|
|
239
254
|
return new JetstreamRecord(this.data, new Map(this.headers), this.timeout);
|
|
240
255
|
}
|
|
@@ -270,7 +285,14 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
|
|
|
270
285
|
pendingTimeouts = /* @__PURE__ */ new Map();
|
|
271
286
|
/** Subscription to connection status events for disconnect handling. */
|
|
272
287
|
statusSubscription = null;
|
|
273
|
-
/**
|
|
288
|
+
/**
|
|
289
|
+
* Establish connection. Called automatically by NestJS on first use.
|
|
290
|
+
*
|
|
291
|
+
* Sets up the JetStream RPC inbox (if in JetStream mode) and subscribes
|
|
292
|
+
* to connection status events for fail-fast disconnect handling.
|
|
293
|
+
*
|
|
294
|
+
* @returns The underlying NATS connection.
|
|
295
|
+
*/
|
|
274
296
|
async connect() {
|
|
275
297
|
const nc = await this.connection.getConnection();
|
|
276
298
|
if (this.isJetStreamRpcMode() && !this.inboxSubscription) {
|
|
@@ -283,15 +305,23 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
|
|
|
283
305
|
});
|
|
284
306
|
return nc;
|
|
285
307
|
}
|
|
286
|
-
/** Clean up resources. */
|
|
308
|
+
/** Clean up resources: reject pending RPCs, unsubscribe from status events. */
|
|
287
309
|
async close() {
|
|
288
310
|
this.statusSubscription?.unsubscribe();
|
|
289
311
|
this.statusSubscription = null;
|
|
290
312
|
this.rejectPendingRpcs(new Error("Client closed"));
|
|
291
313
|
}
|
|
292
|
-
/**
|
|
314
|
+
/**
|
|
315
|
+
* Direct access to the raw NATS connection.
|
|
316
|
+
*
|
|
317
|
+
* @throws Error if not connected.
|
|
318
|
+
*/
|
|
293
319
|
unwrap() {
|
|
294
|
-
|
|
320
|
+
const nc = this.connection.unwrap;
|
|
321
|
+
if (!nc) {
|
|
322
|
+
throw new Error("Not connected \u2014 call connect() before unwrap()");
|
|
323
|
+
}
|
|
324
|
+
return nc;
|
|
295
325
|
}
|
|
296
326
|
/**
|
|
297
327
|
* Publish a fire-and-forget event to JetStream.
|
|
@@ -304,10 +334,13 @@ var JetstreamClient = class extends import_microservices.ClientProxy {
|
|
|
304
334
|
const { data, hdrs } = this.extractRecordData(packet.data);
|
|
305
335
|
const subject = this.buildEventSubject(packet.pattern);
|
|
306
336
|
const msgHeaders = this.buildHeaders(hdrs, { subject });
|
|
307
|
-
await nc.jetstream().publish(subject, this.codec.encode(data), {
|
|
337
|
+
const ack = await nc.jetstream().publish(subject, this.codec.encode(data), {
|
|
308
338
|
headers: msgHeaders,
|
|
309
339
|
msgID: crypto.randomUUID()
|
|
310
340
|
});
|
|
341
|
+
if (ack.duplicate) {
|
|
342
|
+
this.logger.warn(`Duplicate event publish detected: ${subject} (seq: ${ack.seq})`);
|
|
343
|
+
}
|
|
311
344
|
return void 0;
|
|
312
345
|
}
|
|
313
346
|
/**
|
|
@@ -571,11 +604,16 @@ var ConnectionProvider = class {
|
|
|
571
604
|
if (this.connectionPromise) {
|
|
572
605
|
return this.connectionPromise;
|
|
573
606
|
}
|
|
574
|
-
this.connectionPromise = this.establish()
|
|
607
|
+
this.connectionPromise = this.establish().catch((err) => {
|
|
608
|
+
this.connectionPromise = null;
|
|
609
|
+
throw err;
|
|
610
|
+
});
|
|
575
611
|
return this.connectionPromise;
|
|
576
612
|
}
|
|
577
613
|
/**
|
|
578
|
-
* Get JetStream manager. Cached after first call.
|
|
614
|
+
* Get the JetStream manager. Cached after first call.
|
|
615
|
+
*
|
|
616
|
+
* @returns The JetStreamManager for stream/consumer administration.
|
|
579
617
|
*/
|
|
580
618
|
async getJetStreamManager() {
|
|
581
619
|
if (this.jsmInstance) return this.jsmInstance;
|
|
@@ -584,7 +622,7 @@ var ConnectionProvider = class {
|
|
|
584
622
|
this.logger.log("JetStream manager initialized");
|
|
585
623
|
return this.jsmInstance;
|
|
586
624
|
}
|
|
587
|
-
/** Direct access to the raw NATS connection
|
|
625
|
+
/** Direct access to the raw NATS connection, or `null` if not yet connected. */
|
|
588
626
|
get unwrap() {
|
|
589
627
|
return this.connection;
|
|
590
628
|
}
|
|
@@ -624,8 +662,7 @@ var ConnectionProvider = class {
|
|
|
624
662
|
this.monitorStatus(nc);
|
|
625
663
|
return nc;
|
|
626
664
|
} catch (err) {
|
|
627
|
-
|
|
628
|
-
if (natsErr.code === "CONNECTION_REFUSED") {
|
|
665
|
+
if (err instanceof import_nats4.NatsError && err.code === "CONNECTION_REFUSED") {
|
|
629
666
|
throw new Error(`NATS connection refused: ${this.options.servers.join(", ")}`);
|
|
630
667
|
}
|
|
631
668
|
throw err;
|
|
@@ -669,53 +706,21 @@ var EventBus = class {
|
|
|
669
706
|
this.logger = logger;
|
|
670
707
|
this.hooks = hooks ?? {};
|
|
671
708
|
}
|
|
672
|
-
/**
|
|
709
|
+
/**
|
|
710
|
+
* Emit a lifecycle event. Dispatches to custom hook if registered, otherwise no-op.
|
|
711
|
+
*
|
|
712
|
+
* @param event - The {@link TransportEvent} to emit.
|
|
713
|
+
* @param args - Arguments matching the hook signature for this event.
|
|
714
|
+
*/
|
|
673
715
|
emit(event, ...args) {
|
|
674
716
|
const hook = this.hooks[event];
|
|
675
|
-
if (hook)
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
}
|
|
683
|
-
return;
|
|
684
|
-
}
|
|
685
|
-
this.defaultHandler(event, args);
|
|
686
|
-
}
|
|
687
|
-
/** Default Logger-based handlers for each event type. */
|
|
688
|
-
defaultHandler(event, args) {
|
|
689
|
-
switch (event) {
|
|
690
|
-
case "connect" /* Connect */:
|
|
691
|
-
this.logger.log(`Connected to NATS: ${args[0]}`);
|
|
692
|
-
break;
|
|
693
|
-
case "disconnect" /* Disconnect */:
|
|
694
|
-
this.logger.warn("NATS connection lost");
|
|
695
|
-
break;
|
|
696
|
-
case "reconnect" /* Reconnect */:
|
|
697
|
-
this.logger.log(`Reconnected to NATS: ${args[0]}`);
|
|
698
|
-
break;
|
|
699
|
-
case "error" /* Error */:
|
|
700
|
-
this.logger.error(`Transport error: ${args[0]}`, args[1] ?? "");
|
|
701
|
-
break;
|
|
702
|
-
case "rpcTimeout" /* RpcTimeout */:
|
|
703
|
-
this.logger.warn(`RPC timeout: ${args[0]} (cid: ${args[1]})`);
|
|
704
|
-
break;
|
|
705
|
-
case "messageRouted" /* MessageRouted */:
|
|
706
|
-
this.logger.debug(`Message routed: ${args[0]} [${args[1]}]`);
|
|
707
|
-
break;
|
|
708
|
-
case "shutdownStart" /* ShutdownStart */:
|
|
709
|
-
this.logger.log("Graceful shutdown initiated");
|
|
710
|
-
break;
|
|
711
|
-
case "shutdownComplete" /* ShutdownComplete */:
|
|
712
|
-
this.logger.log("Graceful shutdown complete");
|
|
713
|
-
break;
|
|
714
|
-
case "deadLetter" /* DeadLetter */: {
|
|
715
|
-
const info = args[0];
|
|
716
|
-
this.logger.warn(`Dead letter: ${info?.subject ?? "unknown"}`);
|
|
717
|
-
break;
|
|
718
|
-
}
|
|
717
|
+
if (!hook) return;
|
|
718
|
+
try {
|
|
719
|
+
hook(...args);
|
|
720
|
+
} catch (err) {
|
|
721
|
+
this.logger.error(
|
|
722
|
+
`Hook "${event}" threw an error: ${err instanceof Error ? err.message : err}`
|
|
723
|
+
);
|
|
719
724
|
}
|
|
720
725
|
}
|
|
721
726
|
};
|
|
@@ -732,6 +737,8 @@ var JetstreamHealthIndicator = class {
|
|
|
732
737
|
*
|
|
733
738
|
* Returns the current connection status without throwing.
|
|
734
739
|
* Use this for custom health endpoints or monitoring integrations.
|
|
740
|
+
*
|
|
741
|
+
* @returns Connection status with server URL and RTT latency.
|
|
735
742
|
*/
|
|
736
743
|
async check() {
|
|
737
744
|
const nc = this.connection.unwrap;
|
|
@@ -754,7 +761,9 @@ var JetstreamHealthIndicator = class {
|
|
|
754
761
|
* Returns `{ [key]: { status: 'up', ... } }` on success.
|
|
755
762
|
* Throws an error with `{ [key]: { status: 'down', ... } }` on failure.
|
|
756
763
|
*
|
|
757
|
-
* @param key Health indicator key (default: 'jetstream')
|
|
764
|
+
* @param key - Health indicator key (default: `'jetstream'`).
|
|
765
|
+
* @returns Object with status, server, and latency under the given key.
|
|
766
|
+
* @throws Error with `{ [key]: { status: 'down' } }` when disconnected.
|
|
758
767
|
*/
|
|
759
768
|
async isHealthy(key = "jetstream") {
|
|
760
769
|
const status = await this.check();
|
|
@@ -793,12 +802,18 @@ var JetstreamStrategy = class extends import_microservices2.Server {
|
|
|
793
802
|
transportId = /* @__PURE__ */ Symbol("jetstream-transport");
|
|
794
803
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
795
804
|
listeners = /* @__PURE__ */ new Map();
|
|
805
|
+
started = false;
|
|
796
806
|
/**
|
|
797
807
|
* Start the transport: register handlers, create infrastructure, begin consumption.
|
|
798
808
|
*
|
|
799
809
|
* Called by NestJS when `connectMicroservice()` is used, or internally by the module.
|
|
800
810
|
*/
|
|
801
811
|
async listen(callback) {
|
|
812
|
+
if (this.started) {
|
|
813
|
+
this.logger.warn("listen() called more than once \u2014 ignoring");
|
|
814
|
+
return;
|
|
815
|
+
}
|
|
816
|
+
this.started = true;
|
|
802
817
|
this.patternRegistry.registerHandlers(this.getHandlers());
|
|
803
818
|
const streamKinds = this.resolveStreamKinds();
|
|
804
819
|
if (streamKinds.length > 0) {
|
|
@@ -817,17 +832,18 @@ var JetstreamStrategy = class extends import_microservices2.Server {
|
|
|
817
832
|
}
|
|
818
833
|
callback();
|
|
819
834
|
}
|
|
820
|
-
/**
|
|
835
|
+
/** Stop all consumers, routers, and subscriptions. Called during shutdown. */
|
|
821
836
|
close() {
|
|
822
837
|
this.eventRouter.destroy();
|
|
823
838
|
this.rpcRouter.destroy();
|
|
824
839
|
this.coreRpcServer.stop();
|
|
825
840
|
this.messageProvider.destroy();
|
|
841
|
+
this.started = false;
|
|
826
842
|
}
|
|
827
843
|
/**
|
|
828
844
|
* Register event listener (required by Server base class).
|
|
829
845
|
*
|
|
830
|
-
* Stores callbacks for
|
|
846
|
+
* Stores callbacks for client use. Primary lifecycle events
|
|
831
847
|
* are routed through EventBus.
|
|
832
848
|
*/
|
|
833
849
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
@@ -836,9 +852,17 @@ var JetstreamStrategy = class extends import_microservices2.Server {
|
|
|
836
852
|
existing.push(callback);
|
|
837
853
|
this.listeners.set(event, existing);
|
|
838
854
|
}
|
|
839
|
-
/**
|
|
855
|
+
/**
|
|
856
|
+
* Unwrap the underlying NATS connection.
|
|
857
|
+
*
|
|
858
|
+
* @throws Error if the transport has not started.
|
|
859
|
+
*/
|
|
840
860
|
unwrap() {
|
|
841
|
-
|
|
861
|
+
const nc = this.connection.unwrap;
|
|
862
|
+
if (!nc) {
|
|
863
|
+
throw new Error("Not connected \u2014 transport has not started");
|
|
864
|
+
}
|
|
865
|
+
return nc;
|
|
842
866
|
}
|
|
843
867
|
/** Access the pattern registry (for module-level introspection). */
|
|
844
868
|
getPatternRegistry() {
|
|
@@ -873,23 +897,37 @@ var import_nats5 = require("nats");
|
|
|
873
897
|
// src/context/rpc.context.ts
|
|
874
898
|
var import_microservices3 = require("@nestjs/microservices");
|
|
875
899
|
var RpcContext = class extends import_microservices3.BaseRpcContext {
|
|
876
|
-
/**
|
|
900
|
+
/**
|
|
901
|
+
* Get the underlying NATS message.
|
|
902
|
+
*
|
|
903
|
+
* @returns `JsMsg` for JetStream handlers, `Msg` for Core RPC handlers.
|
|
904
|
+
*/
|
|
877
905
|
getMessage() {
|
|
878
906
|
return this.args[0];
|
|
879
907
|
}
|
|
880
|
-
/**
|
|
908
|
+
/** @returns The NATS subject this message was published to. */
|
|
881
909
|
getSubject() {
|
|
882
910
|
return this.args[0].subject;
|
|
883
911
|
}
|
|
884
|
-
/**
|
|
912
|
+
/** @returns All NATS message headers, or `undefined` if none are present. */
|
|
885
913
|
getHeaders() {
|
|
886
914
|
return this.args[0].headers;
|
|
887
915
|
}
|
|
888
|
-
/**
|
|
916
|
+
/**
|
|
917
|
+
* Get a single header value by key.
|
|
918
|
+
*
|
|
919
|
+
* @param key - Header name (e.g. `'x-trace-id'`).
|
|
920
|
+
* @returns Header value, or `undefined` if the header is missing.
|
|
921
|
+
*/
|
|
889
922
|
getHeader(key) {
|
|
890
923
|
return this.args[0].headers?.get(key);
|
|
891
924
|
}
|
|
892
|
-
/**
|
|
925
|
+
/**
|
|
926
|
+
* Type guard: returns `true` when the message is a JetStream message.
|
|
927
|
+
*
|
|
928
|
+
* Narrows `getMessage()` return type to `JsMsg`, giving access to
|
|
929
|
+
* `ack()`, `nak()`, `term()`, and delivery metadata.
|
|
930
|
+
*/
|
|
893
931
|
isJetStream() {
|
|
894
932
|
return "ack" in this.args[0];
|
|
895
933
|
}
|
|
@@ -1008,6 +1046,7 @@ var CoreRpcServer = class {
|
|
|
1008
1046
|
|
|
1009
1047
|
// src/server/infrastructure/stream.provider.ts
|
|
1010
1048
|
var import_common5 = require("@nestjs/common");
|
|
1049
|
+
var import_nats6 = require("nats");
|
|
1011
1050
|
var STREAM_NOT_FOUND = 10059;
|
|
1012
1051
|
var StreamProvider = class {
|
|
1013
1052
|
constructor(options, connection) {
|
|
@@ -1050,8 +1089,7 @@ var StreamProvider = class {
|
|
|
1050
1089
|
this.logger.debug(`Stream exists, updating: ${config.name}`);
|
|
1051
1090
|
return await jsm.streams.update(config.name, config);
|
|
1052
1091
|
} catch (err) {
|
|
1053
|
-
|
|
1054
|
-
if (natsErr.api_error?.err_code === STREAM_NOT_FOUND) {
|
|
1092
|
+
if (err instanceof import_nats6.NatsError && err.api_error?.err_code === STREAM_NOT_FOUND) {
|
|
1055
1093
|
this.logger.log(`Creating stream: ${config.name}`);
|
|
1056
1094
|
return await jsm.streams.add(config);
|
|
1057
1095
|
}
|
|
@@ -1099,6 +1137,7 @@ var StreamProvider = class {
|
|
|
1099
1137
|
|
|
1100
1138
|
// src/server/infrastructure/consumer.provider.ts
|
|
1101
1139
|
var import_common6 = require("@nestjs/common");
|
|
1140
|
+
var import_nats7 = require("nats");
|
|
1102
1141
|
var CONSUMER_NOT_FOUND = 10014;
|
|
1103
1142
|
var ConsumerProvider = class {
|
|
1104
1143
|
constructor(options, connection, streamProvider, patternRegistry) {
|
|
@@ -1139,8 +1178,7 @@ var ConsumerProvider = class {
|
|
|
1139
1178
|
this.logger.debug(`Consumer exists: ${name}`);
|
|
1140
1179
|
return info;
|
|
1141
1180
|
} catch (err) {
|
|
1142
|
-
|
|
1143
|
-
if (natsErr.api_error?.err_code === CONSUMER_NOT_FOUND) {
|
|
1181
|
+
if (err instanceof import_nats7.NatsError && err.api_error?.err_code === CONSUMER_NOT_FOUND) {
|
|
1144
1182
|
this.logger.log(`Creating consumer: ${name}`);
|
|
1145
1183
|
return await jsm.consumers.add(stream, config);
|
|
1146
1184
|
}
|
|
@@ -1216,6 +1254,7 @@ var MessageProvider = class {
|
|
|
1216
1254
|
}
|
|
1217
1255
|
logger = new import_common7.Logger("Jetstream:Message");
|
|
1218
1256
|
destroy$ = new import_rxjs3.Subject();
|
|
1257
|
+
activeIterators = /* @__PURE__ */ new Set();
|
|
1219
1258
|
eventMessages$ = new import_rxjs3.Subject();
|
|
1220
1259
|
commandMessages$ = new import_rxjs3.Subject();
|
|
1221
1260
|
broadcastMessages$ = new import_rxjs3.Subject();
|
|
@@ -1250,6 +1289,10 @@ var MessageProvider = class {
|
|
|
1250
1289
|
destroy() {
|
|
1251
1290
|
this.destroy$.next();
|
|
1252
1291
|
this.destroy$.complete();
|
|
1292
|
+
for (const messages of this.activeIterators) {
|
|
1293
|
+
messages.stop();
|
|
1294
|
+
}
|
|
1295
|
+
this.activeIterators.clear();
|
|
1253
1296
|
this.eventMessages$.complete();
|
|
1254
1297
|
this.commandMessages$.complete();
|
|
1255
1298
|
this.broadcastMessages$.complete();
|
|
@@ -1257,8 +1300,13 @@ var MessageProvider = class {
|
|
|
1257
1300
|
/** Create a self-healing consumer flow for a specific kind. */
|
|
1258
1301
|
createFlow(kind, info) {
|
|
1259
1302
|
const target$ = this.getTargetSubject(kind);
|
|
1303
|
+
let consecutiveFailures = 0;
|
|
1260
1304
|
return (0, import_rxjs3.defer)(() => this.consumeOnce(info, target$)).pipe(
|
|
1305
|
+
(0, import_rxjs3.tap)(() => {
|
|
1306
|
+
consecutiveFailures = 0;
|
|
1307
|
+
}),
|
|
1261
1308
|
(0, import_rxjs3.catchError)((err) => {
|
|
1309
|
+
consecutiveFailures++;
|
|
1262
1310
|
this.logger.error(`Consumer ${info.name} error, will restart:`, err);
|
|
1263
1311
|
this.eventBus.emit(
|
|
1264
1312
|
"error" /* Error */,
|
|
@@ -1269,13 +1317,14 @@ var MessageProvider = class {
|
|
|
1269
1317
|
}),
|
|
1270
1318
|
(0, import_rxjs3.repeat)({
|
|
1271
1319
|
delay: () => {
|
|
1272
|
-
|
|
1320
|
+
const delay = Math.min(100 * Math.pow(2, consecutiveFailures), 3e4);
|
|
1321
|
+
this.logger.warn(`Consumer ${info.name} stream ended, restarting in ${delay}ms...`);
|
|
1273
1322
|
this.eventBus.emit(
|
|
1274
1323
|
"error" /* Error */,
|
|
1275
1324
|
new Error(`Consumer ${info.name} stream ended`),
|
|
1276
1325
|
"message-provider"
|
|
1277
1326
|
);
|
|
1278
|
-
return (0, import_rxjs3.timer)(
|
|
1327
|
+
return (0, import_rxjs3.timer)(delay);
|
|
1279
1328
|
}
|
|
1280
1329
|
}),
|
|
1281
1330
|
(0, import_rxjs3.takeUntil)(this.destroy$)
|
|
@@ -1286,8 +1335,13 @@ var MessageProvider = class {
|
|
|
1286
1335
|
const js = (await this.connection.getConnection()).jetstream();
|
|
1287
1336
|
const consumer = await js.consumers.get(info.stream_name, info.name);
|
|
1288
1337
|
const messages = await consumer.consume();
|
|
1289
|
-
|
|
1290
|
-
|
|
1338
|
+
this.activeIterators.add(messages);
|
|
1339
|
+
try {
|
|
1340
|
+
for await (const msg of messages) {
|
|
1341
|
+
target$.next(msg);
|
|
1342
|
+
}
|
|
1343
|
+
} finally {
|
|
1344
|
+
this.activeIterators.delete(messages);
|
|
1291
1345
|
}
|
|
1292
1346
|
}
|
|
1293
1347
|
/** Get the target subject for a consumer kind. */
|
|
@@ -1427,11 +1481,14 @@ var EventRouter = class {
|
|
|
1427
1481
|
/** Subscribe to a message stream and route each message. */
|
|
1428
1482
|
subscribeToStream(stream$, label) {
|
|
1429
1483
|
const subscription = stream$.pipe(
|
|
1430
|
-
(0, import_rxjs4.mergeMap)(
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1484
|
+
(0, import_rxjs4.mergeMap)(
|
|
1485
|
+
(msg) => (0, import_rxjs4.defer)(() => this.handle(msg)).pipe(
|
|
1486
|
+
(0, import_rxjs4.catchError)((err) => {
|
|
1487
|
+
this.logger.error(`Unexpected error in ${label} event router`, err);
|
|
1488
|
+
return import_rxjs4.EMPTY;
|
|
1489
|
+
})
|
|
1490
|
+
)
|
|
1491
|
+
)
|
|
1435
1492
|
).subscribe();
|
|
1436
1493
|
this.subscriptions.push(subscription);
|
|
1437
1494
|
}
|
|
@@ -1505,7 +1562,7 @@ var EventRouter = class {
|
|
|
1505
1562
|
|
|
1506
1563
|
// src/server/routing/rpc.router.ts
|
|
1507
1564
|
var import_common10 = require("@nestjs/common");
|
|
1508
|
-
var
|
|
1565
|
+
var import_nats8 = require("nats");
|
|
1509
1566
|
var import_rxjs5 = require("rxjs");
|
|
1510
1567
|
var RpcRouter = class {
|
|
1511
1568
|
constructor(messageProvider, patternRegistry, connection, codec, eventBus, timeout) {
|
|
@@ -1522,11 +1579,14 @@ var RpcRouter = class {
|
|
|
1522
1579
|
/** Start routing command messages to handlers. */
|
|
1523
1580
|
start() {
|
|
1524
1581
|
this.subscription = this.messageProvider.commands$.pipe(
|
|
1525
|
-
(0, import_rxjs5.mergeMap)(
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1582
|
+
(0, import_rxjs5.mergeMap)(
|
|
1583
|
+
(msg) => (0, import_rxjs5.defer)(() => this.handle(msg)).pipe(
|
|
1584
|
+
(0, import_rxjs5.catchError)((err) => {
|
|
1585
|
+
this.logger.error("Unexpected error in RPC router", err);
|
|
1586
|
+
return import_rxjs5.EMPTY;
|
|
1587
|
+
})
|
|
1588
|
+
)
|
|
1589
|
+
)
|
|
1530
1590
|
).subscribe();
|
|
1531
1591
|
}
|
|
1532
1592
|
/** Stop routing and unsubscribe. */
|
|
@@ -1564,7 +1624,7 @@ var RpcRouter = class {
|
|
|
1564
1624
|
async executeHandler(handler, data, msg, replyTo, correlationId) {
|
|
1565
1625
|
const nc = await this.connection.getConnection();
|
|
1566
1626
|
const ctx = new RpcContext([msg]);
|
|
1567
|
-
const hdrs = (0,
|
|
1627
|
+
const hdrs = (0, import_nats8.headers)();
|
|
1568
1628
|
hdrs.set("x-correlation-id" /* CorrelationId */, correlationId);
|
|
1569
1629
|
let settled = false;
|
|
1570
1630
|
const timeoutId = setTimeout(() => {
|
|
@@ -1579,8 +1639,12 @@ var RpcRouter = class {
|
|
|
1579
1639
|
if (settled) return;
|
|
1580
1640
|
settled = true;
|
|
1581
1641
|
clearTimeout(timeoutId);
|
|
1582
|
-
nc.publish(replyTo, this.codec.encode(result), { headers: hdrs });
|
|
1583
1642
|
msg.ack();
|
|
1643
|
+
try {
|
|
1644
|
+
nc.publish(replyTo, this.codec.encode(result), { headers: hdrs });
|
|
1645
|
+
} catch (publishErr) {
|
|
1646
|
+
this.logger.error(`Failed to publish RPC response for ${msg.subject}`, publishErr);
|
|
1647
|
+
}
|
|
1584
1648
|
} catch (err) {
|
|
1585
1649
|
if (settled) return;
|
|
1586
1650
|
settled = true;
|
|
@@ -1614,10 +1678,17 @@ var ShutdownManager = class {
|
|
|
1614
1678
|
this.eventBus.emit("shutdownStart" /* ShutdownStart */);
|
|
1615
1679
|
this.logger.log(`Graceful shutdown started (timeout: ${this.timeout}ms)`);
|
|
1616
1680
|
strategy?.close();
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1681
|
+
let timeoutId;
|
|
1682
|
+
try {
|
|
1683
|
+
await Promise.race([
|
|
1684
|
+
this.connection.shutdown(),
|
|
1685
|
+
new Promise((resolve) => {
|
|
1686
|
+
timeoutId = setTimeout(resolve, this.timeout);
|
|
1687
|
+
})
|
|
1688
|
+
]);
|
|
1689
|
+
} finally {
|
|
1690
|
+
clearTimeout(timeoutId);
|
|
1691
|
+
}
|
|
1621
1692
|
this.eventBus.emit("shutdownComplete" /* ShutdownComplete */);
|
|
1622
1693
|
this.logger.log("Graceful shutdown complete");
|
|
1623
1694
|
}
|