@horizon-republic/nestjs-jetstream 2.9.1 → 2.10.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/dist/index.cjs +1515 -272
- package/dist/index.d.cts +965 -654
- package/dist/index.d.ts +965 -654
- package/dist/index.js +1515 -263
- package/package.json +16 -7
package/dist/index.js
CHANGED
|
@@ -14,19 +14,21 @@ var __decorateParam = (index, decorator) => (target, key) => decorator(target, k
|
|
|
14
14
|
import {
|
|
15
15
|
Global,
|
|
16
16
|
Inject,
|
|
17
|
-
Logger as
|
|
17
|
+
Logger as Logger18,
|
|
18
18
|
Module,
|
|
19
19
|
Optional
|
|
20
20
|
} from "@nestjs/common";
|
|
21
21
|
|
|
22
22
|
// src/client/jetstream.client.ts
|
|
23
|
-
import { Logger } from "@nestjs/common";
|
|
23
|
+
import { Logger as Logger5 } from "@nestjs/common";
|
|
24
24
|
import { ClientProxy } from "@nestjs/microservices";
|
|
25
|
+
import { context as context6 } from "@opentelemetry/api";
|
|
26
|
+
import { nuid } from "@nats-io/nuid";
|
|
25
27
|
import {
|
|
26
28
|
createInbox,
|
|
27
|
-
headers as natsHeaders
|
|
29
|
+
headers as natsHeaders,
|
|
30
|
+
TimeoutError
|
|
28
31
|
} from "@nats-io/transport-node";
|
|
29
|
-
import { nuid } from "@nats-io/nuid";
|
|
30
32
|
|
|
31
33
|
// src/interfaces/hooks.interface.ts
|
|
32
34
|
var MessageKind = /* @__PURE__ */ ((MessageKind2) => {
|
|
@@ -224,6 +226,920 @@ var PatternPrefix = /* @__PURE__ */ ((PatternPrefix2) => {
|
|
|
224
226
|
var isJetStreamRpcMode = (rpc) => rpc?.mode === "jetstream";
|
|
225
227
|
var isCoreRpcMode = (rpc) => !rpc || rpc.mode === "core";
|
|
226
228
|
|
|
229
|
+
// src/otel/constants.ts
|
|
230
|
+
var TRACER_NAME = "@horizon-republic/nestjs-jetstream";
|
|
231
|
+
|
|
232
|
+
// src/otel/attribute-keys.ts
|
|
233
|
+
var ATTR_MESSAGING_SYSTEM = "messaging.system";
|
|
234
|
+
var ATTR_MESSAGING_DESTINATION_NAME = "messaging.destination.name";
|
|
235
|
+
var ATTR_MESSAGING_DESTINATION_TEMPLATE = "messaging.destination.template";
|
|
236
|
+
var ATTR_MESSAGING_CLIENT_ID = "messaging.client.id";
|
|
237
|
+
var ATTR_MESSAGING_OPERATION_NAME = "messaging.operation.name";
|
|
238
|
+
var ATTR_MESSAGING_OPERATION_TYPE = "messaging.operation.type";
|
|
239
|
+
var ATTR_MESSAGING_MESSAGE_BODY_SIZE = "messaging.message.body.size";
|
|
240
|
+
var ATTR_MESSAGING_MESSAGE_ID = "messaging.message.id";
|
|
241
|
+
var ATTR_MESSAGING_MESSAGE_CONVERSATION_ID = "messaging.message.conversation_id";
|
|
242
|
+
var ATTR_MESSAGING_CONSUMER_GROUP_NAME = "messaging.consumer.group.name";
|
|
243
|
+
var ATTR_MESSAGING_HEADER_PREFIX = "messaging.header.";
|
|
244
|
+
var ATTR_MESSAGING_NATS_STREAM_NAME = "messaging.nats.stream.name";
|
|
245
|
+
var ATTR_MESSAGING_NATS_STREAM_SEQUENCE = "messaging.nats.message.stream_sequence";
|
|
246
|
+
var ATTR_MESSAGING_NATS_CONSUMER_SEQUENCE = "messaging.nats.message.consumer_sequence";
|
|
247
|
+
var ATTR_MESSAGING_NATS_DELIVERY_COUNT = "messaging.nats.message.delivery_count";
|
|
248
|
+
var ATTR_MESSAGING_NATS_BODY = "messaging.nats.message.body";
|
|
249
|
+
var ATTR_MESSAGING_NATS_BODY_TRUNCATED = "messaging.nats.message.body.truncated";
|
|
250
|
+
var ATTR_SERVER_ADDRESS = "server.address";
|
|
251
|
+
var ATTR_SERVER_PORT = "server.port";
|
|
252
|
+
var ATTR_JETSTREAM_SERVICE_NAME = "jetstream.service.name";
|
|
253
|
+
var ATTR_JETSTREAM_KIND = "jetstream.kind";
|
|
254
|
+
var ATTR_JETSTREAM_RPC_REPLY_HAS_ERROR = "jetstream.rpc.reply.has_error";
|
|
255
|
+
var ATTR_JETSTREAM_RPC_REPLY_ERROR_CODE = "jetstream.rpc.reply.error.code";
|
|
256
|
+
var ATTR_JETSTREAM_PROVISIONING_ENTITY = "jetstream.provisioning.entity";
|
|
257
|
+
var ATTR_JETSTREAM_PROVISIONING_ACTION = "jetstream.provisioning.action";
|
|
258
|
+
var ATTR_JETSTREAM_PROVISIONING_NAME = "jetstream.provisioning.name";
|
|
259
|
+
var ATTR_JETSTREAM_SELF_HEALING_REASON = "jetstream.self_healing.reason";
|
|
260
|
+
var ATTR_JETSTREAM_MIGRATION_REASON = "jetstream.migration.reason";
|
|
261
|
+
var ATTR_JETSTREAM_DEAD_LETTER_REASON = "jetstream.dead_letter.reason";
|
|
262
|
+
var ATTR_JETSTREAM_SCHEDULE_TARGET = "jetstream.schedule.target";
|
|
263
|
+
var ATTR_NATS_CONNECTION_SERVER = "nats.connection.server";
|
|
264
|
+
var NATS_MSG_ID_HEADER = "Nats-Msg-Id";
|
|
265
|
+
var HOOK_PUBLISH = "publishHook";
|
|
266
|
+
var HOOK_CONSUME = "consumeHook";
|
|
267
|
+
var HOOK_RESPONSE = "responseHook";
|
|
268
|
+
var SPAN_NAME_PUBLISH = "publish";
|
|
269
|
+
var SPAN_NAME_PROCESS = "process";
|
|
270
|
+
var SPAN_NAME_SEND = "send";
|
|
271
|
+
var SPAN_NAME_DEAD_LETTER = "dead_letter";
|
|
272
|
+
var SPAN_NAME_NATS_CONNECTION = "nats.connection";
|
|
273
|
+
var SPAN_NAME_JETSTREAM_SHUTDOWN = "jetstream.shutdown";
|
|
274
|
+
var SPAN_NAME_JETSTREAM_SELF_HEALING = "jetstream.self_healing";
|
|
275
|
+
var SPAN_NAME_JETSTREAM_MIGRATION = "jetstream.migration";
|
|
276
|
+
var SPAN_NAME_JETSTREAM_PROVISIONING_PREFIX = "jetstream.provisioning.";
|
|
277
|
+
var EVENT_CONNECTION_DISCONNECTED = "connection.disconnected";
|
|
278
|
+
var EVENT_CONNECTION_RECONNECTED = "connection.reconnected";
|
|
279
|
+
var messagingHeaderAttr = (headerName) => `${ATTR_MESSAGING_HEADER_PREFIX}${headerName.toLowerCase()}`;
|
|
280
|
+
|
|
281
|
+
// src/otel/trace-kinds.ts
|
|
282
|
+
var JetstreamTrace = /* @__PURE__ */ ((JetstreamTrace2) => {
|
|
283
|
+
JetstreamTrace2["Publish"] = "publish";
|
|
284
|
+
JetstreamTrace2["Consume"] = "consume";
|
|
285
|
+
JetstreamTrace2["RpcClientSend"] = "rpc.client.send";
|
|
286
|
+
JetstreamTrace2["DeadLetter"] = "dead_letter";
|
|
287
|
+
JetstreamTrace2["ConnectionLifecycle"] = "connection.lifecycle";
|
|
288
|
+
JetstreamTrace2["SelfHealing"] = "self_healing";
|
|
289
|
+
JetstreamTrace2["Provisioning"] = "provisioning";
|
|
290
|
+
JetstreamTrace2["Migration"] = "migration";
|
|
291
|
+
JetstreamTrace2["Shutdown"] = "shutdown";
|
|
292
|
+
return JetstreamTrace2;
|
|
293
|
+
})(JetstreamTrace || {});
|
|
294
|
+
var DEFAULT_TRACES = [
|
|
295
|
+
"publish" /* Publish */,
|
|
296
|
+
"consume" /* Consume */,
|
|
297
|
+
"rpc.client.send" /* RpcClientSend */,
|
|
298
|
+
"dead_letter" /* DeadLetter */
|
|
299
|
+
];
|
|
300
|
+
|
|
301
|
+
// src/otel/capture.ts
|
|
302
|
+
var NEGATION_PREFIX = "!";
|
|
303
|
+
var REGEX_SPECIAL_RE = /[.+?^${}()|[\]\\*]/gu;
|
|
304
|
+
var escapeForRegex = (input) => input.replace(REGEX_SPECIAL_RE, "\\$&");
|
|
305
|
+
var globToRegex = (glob) => {
|
|
306
|
+
const escaped = escapeForRegex(glob.toLowerCase()).replace(/\\\*/gu, ".*");
|
|
307
|
+
return new RegExp(`^${escaped}$`, "u");
|
|
308
|
+
};
|
|
309
|
+
var compileHeaderAllowlist = (allowlist) => {
|
|
310
|
+
if (allowlist === true) return () => true;
|
|
311
|
+
if (allowlist === false) return () => false;
|
|
312
|
+
if (allowlist.length === 0) return () => false;
|
|
313
|
+
const includes = [];
|
|
314
|
+
const excludes = [];
|
|
315
|
+
for (const pattern of allowlist) {
|
|
316
|
+
const isExclude = pattern.startsWith(NEGATION_PREFIX);
|
|
317
|
+
const body = isExclude ? pattern.slice(NEGATION_PREFIX.length) : pattern;
|
|
318
|
+
const regex = globToRegex(body);
|
|
319
|
+
if (isExclude) excludes.push(regex);
|
|
320
|
+
else includes.push(regex);
|
|
321
|
+
}
|
|
322
|
+
return (name) => {
|
|
323
|
+
const lower = name.toLowerCase();
|
|
324
|
+
if (!includes.some((re) => re.test(lower))) return false;
|
|
325
|
+
if (excludes.some((re) => re.test(lower))) return false;
|
|
326
|
+
return true;
|
|
327
|
+
};
|
|
328
|
+
};
|
|
329
|
+
var subjectMatcherCache = /* @__PURE__ */ new WeakMap();
|
|
330
|
+
var compileSubjectAllowlist = (allowlist) => {
|
|
331
|
+
if (!allowlist || allowlist.length === 0) return () => true;
|
|
332
|
+
const cached = subjectMatcherCache.get(allowlist);
|
|
333
|
+
if (cached) return cached;
|
|
334
|
+
const regexes = allowlist.map(globToRegex);
|
|
335
|
+
const matcher = (subject) => {
|
|
336
|
+
const lower = subject.toLowerCase();
|
|
337
|
+
return regexes.some((re) => re.test(lower));
|
|
338
|
+
};
|
|
339
|
+
subjectMatcherCache.set(allowlist, matcher);
|
|
340
|
+
return matcher;
|
|
341
|
+
};
|
|
342
|
+
var subjectMatchesAllowlist = (subject, allowlist) => compileSubjectAllowlist(allowlist)(subject);
|
|
343
|
+
var HEADER_DENYLIST = /* @__PURE__ */ new Set([
|
|
344
|
+
"traceparent",
|
|
345
|
+
"tracestate",
|
|
346
|
+
"baggage",
|
|
347
|
+
"sentry-trace",
|
|
348
|
+
"b3",
|
|
349
|
+
"x-b3-traceid",
|
|
350
|
+
"x-b3-spanid",
|
|
351
|
+
"x-b3-parentspanid",
|
|
352
|
+
"x-b3-sampled",
|
|
353
|
+
"x-b3-flags",
|
|
354
|
+
"uber-trace-id",
|
|
355
|
+
"x-correlation-id",
|
|
356
|
+
"x-reply-to",
|
|
357
|
+
"x-error",
|
|
358
|
+
"x-subject",
|
|
359
|
+
"x-caller-name"
|
|
360
|
+
]);
|
|
361
|
+
var isNatsServerHeader = (lower) => lower.startsWith("nats-");
|
|
362
|
+
var captureMatchingHeaders = (headers2, matcher) => {
|
|
363
|
+
if (!headers2) return {};
|
|
364
|
+
const out = {};
|
|
365
|
+
for (const key of headers2.keys()) {
|
|
366
|
+
const lower = key.toLowerCase();
|
|
367
|
+
if (HEADER_DENYLIST.has(lower)) continue;
|
|
368
|
+
if (isNatsServerHeader(lower)) continue;
|
|
369
|
+
if (!matcher(key)) continue;
|
|
370
|
+
const value = headers2.get(key);
|
|
371
|
+
if (value === "") continue;
|
|
372
|
+
out[messagingHeaderAttr(lower)] = value;
|
|
373
|
+
}
|
|
374
|
+
return out;
|
|
375
|
+
};
|
|
376
|
+
var tryUtf8Decode = (bytes) => {
|
|
377
|
+
try {
|
|
378
|
+
return new TextDecoder("utf-8", { fatal: false }).decode(bytes);
|
|
379
|
+
} catch {
|
|
380
|
+
return Buffer.from(bytes).toString("base64");
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
var captureBodyAttribute = (subject, payload, capture) => {
|
|
384
|
+
if (capture === false) return {};
|
|
385
|
+
if (payload.byteLength === 0) return {};
|
|
386
|
+
if (!subjectMatchesAllowlist(subject, capture.subjectAllowlist)) return {};
|
|
387
|
+
const { maxBytes } = capture;
|
|
388
|
+
const truncated = payload.byteLength > maxBytes;
|
|
389
|
+
const slice = truncated ? payload.subarray(0, maxBytes) : payload;
|
|
390
|
+
const decoded = tryUtf8Decode(slice);
|
|
391
|
+
const out = { [ATTR_MESSAGING_NATS_BODY]: decoded };
|
|
392
|
+
if (truncated) out[ATTR_MESSAGING_NATS_BODY_TRUNCATED] = true;
|
|
393
|
+
return out;
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
// src/otel/config.ts
|
|
397
|
+
var PublishKind = /* @__PURE__ */ ((PublishKind2) => {
|
|
398
|
+
PublishKind2["Event"] = "event";
|
|
399
|
+
PublishKind2["RpcRequest"] = "rpc.request";
|
|
400
|
+
PublishKind2["Broadcast"] = "broadcast";
|
|
401
|
+
PublishKind2["Ordered"] = "ordered";
|
|
402
|
+
return PublishKind2;
|
|
403
|
+
})(PublishKind || {});
|
|
404
|
+
var ConsumeKind = /* @__PURE__ */ ((ConsumeKind2) => {
|
|
405
|
+
ConsumeKind2["Event"] = "event";
|
|
406
|
+
ConsumeKind2["Rpc"] = "rpc";
|
|
407
|
+
ConsumeKind2["Broadcast"] = "broadcast";
|
|
408
|
+
ConsumeKind2["Ordered"] = "ordered";
|
|
409
|
+
return ConsumeKind2;
|
|
410
|
+
})(ConsumeKind || {});
|
|
411
|
+
var DEFAULT_CAPTURE_HEADERS = ["x-request-id"];
|
|
412
|
+
var DEFAULT_CAPTURE_BODY_MAX_BYTES = 4096;
|
|
413
|
+
var NESTJS_BARE_ERROR_MESSAGE = "Internal server error";
|
|
414
|
+
var isNestjsBareErrorSentinel = (obj) => obj.status === "error" && obj.message === NESTJS_BARE_ERROR_MESSAGE;
|
|
415
|
+
var defaultErrorClassifier = (err) => {
|
|
416
|
+
if (err === null || typeof err !== "object") return "unexpected";
|
|
417
|
+
if (!(err instanceof Error)) {
|
|
418
|
+
if (isNestjsBareErrorSentinel(err)) return "unexpected";
|
|
419
|
+
return "expected";
|
|
420
|
+
}
|
|
421
|
+
let proto = err;
|
|
422
|
+
while (proto) {
|
|
423
|
+
const name = proto.constructor?.name;
|
|
424
|
+
if (name === "RpcException" || name === "HttpException") return "expected";
|
|
425
|
+
proto = Object.getPrototypeOf(proto);
|
|
426
|
+
}
|
|
427
|
+
return "unexpected";
|
|
428
|
+
};
|
|
429
|
+
var expandTracesOption = (option) => {
|
|
430
|
+
if (option === void 0 || option === "default") return new Set(DEFAULT_TRACES);
|
|
431
|
+
if (option === "all") return new Set(Object.values(JetstreamTrace));
|
|
432
|
+
if (option === "none") return /* @__PURE__ */ new Set();
|
|
433
|
+
return new Set(option);
|
|
434
|
+
};
|
|
435
|
+
var compileHeaderMatcher = (option) => compileHeaderAllowlist(option ?? DEFAULT_CAPTURE_HEADERS);
|
|
436
|
+
var resolveCaptureBody = (option) => {
|
|
437
|
+
if (option === void 0 || option === false) return false;
|
|
438
|
+
if (option === true) return { maxBytes: DEFAULT_CAPTURE_BODY_MAX_BYTES };
|
|
439
|
+
return {
|
|
440
|
+
maxBytes: option.maxBytes ?? DEFAULT_CAPTURE_BODY_MAX_BYTES,
|
|
441
|
+
subjectAllowlist: option.subjectAllowlist
|
|
442
|
+
};
|
|
443
|
+
};
|
|
444
|
+
var resolveOtelOptions = (options = {}) => {
|
|
445
|
+
return {
|
|
446
|
+
enabled: options.enabled ?? true,
|
|
447
|
+
traces: expandTracesOption(options.traces),
|
|
448
|
+
captureHeaders: compileHeaderMatcher(options.captureHeaders),
|
|
449
|
+
captureBody: resolveCaptureBody(options.captureBody),
|
|
450
|
+
publishHook: options.publishHook,
|
|
451
|
+
consumeHook: options.consumeHook,
|
|
452
|
+
responseHook: options.responseHook,
|
|
453
|
+
shouldTracePublish: options.shouldTracePublish,
|
|
454
|
+
shouldTraceConsume: options.shouldTraceConsume,
|
|
455
|
+
errorClassifier: options.errorClassifier ?? defaultErrorClassifier
|
|
456
|
+
};
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
// src/otel/internal-utils.ts
|
|
460
|
+
import { Logger } from "@nestjs/common";
|
|
461
|
+
var logger = new Logger("Jetstream:Otel");
|
|
462
|
+
var safelyInvokeHook = (hookName, hook, ...args) => {
|
|
463
|
+
if (!hook) return;
|
|
464
|
+
const logHookFailure = (err) => {
|
|
465
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
466
|
+
logger.debug(`OTel ${hookName} threw: ${message}`);
|
|
467
|
+
};
|
|
468
|
+
try {
|
|
469
|
+
const result = hook(...args);
|
|
470
|
+
if (result !== null && typeof result === "object" && "then" in result && typeof result.then === "function") {
|
|
471
|
+
result.then(void 0, logHookFailure);
|
|
472
|
+
}
|
|
473
|
+
} catch (err) {
|
|
474
|
+
logHookFailure(err);
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
var stripIpv6Brackets = (host) => host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
|
|
478
|
+
var parsePort = (portRaw) => {
|
|
479
|
+
if (!portRaw) return void 0;
|
|
480
|
+
const port = Number.parseInt(portRaw, 10);
|
|
481
|
+
return Number.isInteger(port) ? port : void 0;
|
|
482
|
+
};
|
|
483
|
+
var parseServerAddress = (servers) => {
|
|
484
|
+
const raw = servers[0];
|
|
485
|
+
if (!raw) return null;
|
|
486
|
+
if (raw.includes("://")) {
|
|
487
|
+
try {
|
|
488
|
+
const url = new URL(raw);
|
|
489
|
+
if (url.hostname.length === 0) return null;
|
|
490
|
+
const host2 = stripIpv6Brackets(url.hostname);
|
|
491
|
+
const port2 = parsePort(url.port || void 0);
|
|
492
|
+
return port2 === void 0 ? { host: host2 } : { host: host2, port: port2 };
|
|
493
|
+
} catch {
|
|
494
|
+
return null;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
if (raw.startsWith("[")) {
|
|
498
|
+
const closeIdx = raw.indexOf("]");
|
|
499
|
+
if (closeIdx <= 0) return null;
|
|
500
|
+
const host2 = raw.slice(1, closeIdx);
|
|
501
|
+
const port2 = parsePort(raw.slice(closeIdx + 1).replace(/^:/u, ""));
|
|
502
|
+
return port2 === void 0 ? { host: host2 } : { host: host2, port: port2 };
|
|
503
|
+
}
|
|
504
|
+
const [host, portRaw] = raw.split(":");
|
|
505
|
+
if (!host) return null;
|
|
506
|
+
const port = parsePort(portRaw);
|
|
507
|
+
return port === void 0 ? { host } : { host, port };
|
|
508
|
+
};
|
|
509
|
+
var deriveOtelAttrs = (options) => ({
|
|
510
|
+
otel: resolveOtelOptions(options.otel),
|
|
511
|
+
serviceName: internalName(options.name),
|
|
512
|
+
serverEndpoint: parseServerAddress(options.servers)
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
// src/otel/propagator.ts
|
|
516
|
+
import {
|
|
517
|
+
propagation
|
|
518
|
+
} from "@opentelemetry/api";
|
|
519
|
+
var injectContext = (ctx, carrier, setter) => {
|
|
520
|
+
propagation.inject(ctx, carrier, setter);
|
|
521
|
+
};
|
|
522
|
+
var extractContext = (ctx, carrier, getter) => propagation.extract(ctx, carrier, getter);
|
|
523
|
+
|
|
524
|
+
// src/otel/tracer.ts
|
|
525
|
+
import { trace } from "@opentelemetry/api";
|
|
526
|
+
var PACKAGE_VERSION = true ? "2.10.0" : "0.0.0";
|
|
527
|
+
var getTracer = () => trace.getTracer(TRACER_NAME, PACKAGE_VERSION);
|
|
528
|
+
|
|
529
|
+
// src/otel/carrier.ts
|
|
530
|
+
var hdrsSetter = {
|
|
531
|
+
set: (headers2, key, value) => {
|
|
532
|
+
headers2.set(key, value);
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
var hdrsGetter = {
|
|
536
|
+
keys: (headers2) => headers2 ? headers2.keys() : [],
|
|
537
|
+
get: (headers2, key) => {
|
|
538
|
+
if (!headers2) return void 0;
|
|
539
|
+
const all = typeof headers2.values === "function" ? headers2.values(key) : void 0;
|
|
540
|
+
if (Array.isArray(all)) {
|
|
541
|
+
const nonEmpty = all.filter((value) => value !== "");
|
|
542
|
+
if (nonEmpty.length === 0) return void 0;
|
|
543
|
+
return nonEmpty.join(",");
|
|
544
|
+
}
|
|
545
|
+
const single = headers2.get(key);
|
|
546
|
+
return single === "" ? void 0 : single;
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
// src/otel/attributes.ts
|
|
551
|
+
var MESSAGING_SYSTEM = "nats";
|
|
552
|
+
var baseMessagingAttributes = (ctx) => {
|
|
553
|
+
const attrs = {
|
|
554
|
+
[ATTR_MESSAGING_SYSTEM]: MESSAGING_SYSTEM,
|
|
555
|
+
[ATTR_MESSAGING_DESTINATION_NAME]: ctx.subject,
|
|
556
|
+
[ATTR_MESSAGING_CLIENT_ID]: ctx.serviceName
|
|
557
|
+
};
|
|
558
|
+
if (ctx.serverAddress) attrs[ATTR_SERVER_ADDRESS] = ctx.serverAddress;
|
|
559
|
+
if (ctx.serverPort !== void 0) attrs[ATTR_SERVER_PORT] = ctx.serverPort;
|
|
560
|
+
if (ctx.pattern && ctx.pattern !== ctx.subject) {
|
|
561
|
+
attrs[ATTR_MESSAGING_DESTINATION_TEMPLATE] = ctx.pattern;
|
|
562
|
+
}
|
|
563
|
+
return attrs;
|
|
564
|
+
};
|
|
565
|
+
var jetstreamKindForPublish = (kind) => kind === "rpc.request" /* RpcRequest */ ? "rpc" /* Rpc */ : kind;
|
|
566
|
+
var buildPublishAttributes = (ctx) => {
|
|
567
|
+
const attrs = {
|
|
568
|
+
...baseMessagingAttributes(ctx),
|
|
569
|
+
[ATTR_MESSAGING_OPERATION_NAME]: SPAN_NAME_PUBLISH,
|
|
570
|
+
[ATTR_MESSAGING_OPERATION_TYPE]: SPAN_NAME_SEND,
|
|
571
|
+
[ATTR_MESSAGING_MESSAGE_BODY_SIZE]: ctx.payloadBytes,
|
|
572
|
+
[ATTR_JETSTREAM_KIND]: jetstreamKindForPublish(ctx.kind)
|
|
573
|
+
};
|
|
574
|
+
if (ctx.messageId) attrs[ATTR_MESSAGING_MESSAGE_ID] = ctx.messageId;
|
|
575
|
+
if (ctx.correlationId) attrs[ATTR_MESSAGING_MESSAGE_CONVERSATION_ID] = ctx.correlationId;
|
|
576
|
+
return attrs;
|
|
577
|
+
};
|
|
578
|
+
var buildConsumeAttributes = (ctx) => {
|
|
579
|
+
const { msg, info, kind, payloadBytes } = ctx;
|
|
580
|
+
const attrs = {
|
|
581
|
+
...baseMessagingAttributes(ctx),
|
|
582
|
+
[ATTR_MESSAGING_OPERATION_NAME]: SPAN_NAME_PROCESS,
|
|
583
|
+
[ATTR_MESSAGING_OPERATION_TYPE]: SPAN_NAME_PROCESS,
|
|
584
|
+
[ATTR_MESSAGING_MESSAGE_BODY_SIZE]: payloadBytes,
|
|
585
|
+
[ATTR_JETSTREAM_KIND]: kind
|
|
586
|
+
};
|
|
587
|
+
if (info) {
|
|
588
|
+
attrs[ATTR_MESSAGING_NATS_STREAM_NAME] = info.stream;
|
|
589
|
+
attrs[ATTR_MESSAGING_CONSUMER_GROUP_NAME] = info.consumer;
|
|
590
|
+
attrs[ATTR_MESSAGING_NATS_STREAM_SEQUENCE] = info.streamSequence;
|
|
591
|
+
attrs[ATTR_MESSAGING_NATS_CONSUMER_SEQUENCE] = info.deliverySequence;
|
|
592
|
+
attrs[ATTR_MESSAGING_NATS_DELIVERY_COUNT] = info.deliveryCount;
|
|
593
|
+
}
|
|
594
|
+
const messageId = msg.headers?.get(NATS_MSG_ID_HEADER);
|
|
595
|
+
if (messageId) attrs[ATTR_MESSAGING_MESSAGE_ID] = messageId;
|
|
596
|
+
return attrs;
|
|
597
|
+
};
|
|
598
|
+
var buildRpcClientAttributes = (ctx) => {
|
|
599
|
+
const attrs = {
|
|
600
|
+
...baseMessagingAttributes(ctx),
|
|
601
|
+
[ATTR_MESSAGING_OPERATION_NAME]: SPAN_NAME_SEND,
|
|
602
|
+
[ATTR_MESSAGING_OPERATION_TYPE]: SPAN_NAME_SEND,
|
|
603
|
+
[ATTR_MESSAGING_MESSAGE_BODY_SIZE]: ctx.payloadBytes,
|
|
604
|
+
[ATTR_JETSTREAM_KIND]: "rpc" /* Rpc */
|
|
605
|
+
};
|
|
606
|
+
if (ctx.correlationId) attrs[ATTR_MESSAGING_MESSAGE_CONVERSATION_ID] = ctx.correlationId;
|
|
607
|
+
if (ctx.messageId) attrs[ATTR_MESSAGING_MESSAGE_ID] = ctx.messageId;
|
|
608
|
+
return attrs;
|
|
609
|
+
};
|
|
610
|
+
var buildDeadLetterAttributes = (ctx) => {
|
|
611
|
+
const attrs = {
|
|
612
|
+
...baseMessagingAttributes(ctx),
|
|
613
|
+
[ATTR_MESSAGING_OPERATION_NAME]: SPAN_NAME_DEAD_LETTER,
|
|
614
|
+
[ATTR_MESSAGING_OPERATION_TYPE]: SPAN_NAME_PROCESS,
|
|
615
|
+
[ATTR_MESSAGING_NATS_DELIVERY_COUNT]: ctx.finalDeliveryCount
|
|
616
|
+
};
|
|
617
|
+
if (ctx.reason) attrs[ATTR_JETSTREAM_DEAD_LETTER_REASON] = ctx.reason;
|
|
618
|
+
return attrs;
|
|
619
|
+
};
|
|
620
|
+
var extractFromRpcException = (record) => {
|
|
621
|
+
const getError = record.getError;
|
|
622
|
+
if (typeof getError !== "function") return void 0;
|
|
623
|
+
return codeFromPayload(getError.call(record));
|
|
624
|
+
};
|
|
625
|
+
var extractFromHttpException = (record) => {
|
|
626
|
+
const getStatus = record.getStatus;
|
|
627
|
+
if (typeof getStatus !== "function") return void 0;
|
|
628
|
+
const status = getStatus.call(record);
|
|
629
|
+
return typeof status === "number" && Number.isFinite(status) ? `HTTP_${status}` : void 0;
|
|
630
|
+
};
|
|
631
|
+
var extractFromOwnCode = (record) => {
|
|
632
|
+
const code = record.code ?? record.errorCode;
|
|
633
|
+
return typeof code === "string" && isStableErrorCode(code) ? code : void 0;
|
|
634
|
+
};
|
|
635
|
+
var extractExpectedErrorCode = (err) => {
|
|
636
|
+
if (err === null || typeof err !== "object") return void 0;
|
|
637
|
+
const record = err;
|
|
638
|
+
if (hasAncestorNamed(err, "RpcException")) {
|
|
639
|
+
const fromPayload = extractFromRpcException(record);
|
|
640
|
+
if (fromPayload !== void 0) return fromPayload;
|
|
641
|
+
}
|
|
642
|
+
if (hasAncestorNamed(err, "HttpException")) {
|
|
643
|
+
const fromStatus = extractFromHttpException(record);
|
|
644
|
+
if (fromStatus !== void 0) return fromStatus;
|
|
645
|
+
}
|
|
646
|
+
return extractFromOwnCode(record);
|
|
647
|
+
};
|
|
648
|
+
var hasAncestorNamed = (err, name) => {
|
|
649
|
+
let proto = Object.getPrototypeOf(err);
|
|
650
|
+
while (proto) {
|
|
651
|
+
const ctorName = proto.constructor?.name;
|
|
652
|
+
if (ctorName === name) return true;
|
|
653
|
+
proto = Object.getPrototypeOf(proto);
|
|
654
|
+
}
|
|
655
|
+
return false;
|
|
656
|
+
};
|
|
657
|
+
var STABLE_ERROR_CODE_RE = /^[A-Z][A-Z0-9_]*$/u;
|
|
658
|
+
var isStableErrorCode = (value) => STABLE_ERROR_CODE_RE.test(value);
|
|
659
|
+
var codeFromPayload = (payload) => {
|
|
660
|
+
if (payload === null || payload === void 0) return void 0;
|
|
661
|
+
if (typeof payload === "string") return isStableErrorCode(payload) ? payload : void 0;
|
|
662
|
+
if (typeof payload === "object") {
|
|
663
|
+
const code = payload.code;
|
|
664
|
+
if (typeof code === "string" && isStableErrorCode(code)) return code;
|
|
665
|
+
}
|
|
666
|
+
return void 0;
|
|
667
|
+
};
|
|
668
|
+
var buildExpectedErrorAttributes = (err) => {
|
|
669
|
+
const attrs = {
|
|
670
|
+
[ATTR_JETSTREAM_RPC_REPLY_HAS_ERROR]: true
|
|
671
|
+
};
|
|
672
|
+
const code = extractExpectedErrorCode(err);
|
|
673
|
+
if (code !== void 0) attrs[ATTR_JETSTREAM_RPC_REPLY_ERROR_CODE] = code;
|
|
674
|
+
return attrs;
|
|
675
|
+
};
|
|
676
|
+
var applyExpectedErrorAttributes = (span, err) => {
|
|
677
|
+
span.setAttributes(buildExpectedErrorAttributes(err));
|
|
678
|
+
};
|
|
679
|
+
|
|
680
|
+
// src/otel/spans/publish.ts
|
|
681
|
+
import { Logger as Logger2 } from "@nestjs/common";
|
|
682
|
+
import { SpanKind, SpanStatusCode, context, trace as trace2 } from "@opentelemetry/api";
|
|
683
|
+
var logger2 = new Logger2("Jetstream:Otel");
|
|
684
|
+
var shouldTracePublishSafe = (predicate, subject, record) => {
|
|
685
|
+
if (!predicate) return true;
|
|
686
|
+
try {
|
|
687
|
+
return predicate(subject, record);
|
|
688
|
+
} catch (err) {
|
|
689
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
690
|
+
logger2.debug(`OTel shouldTracePublish threw: ${message}`);
|
|
691
|
+
return true;
|
|
692
|
+
}
|
|
693
|
+
};
|
|
694
|
+
var withPublishSpan = async (ctx, config, fn) => {
|
|
695
|
+
if (!config.enabled) return fn();
|
|
696
|
+
const shouldCreateSpan = config.traces.has("publish" /* Publish */) && shouldTracePublishSafe(config.shouldTracePublish, ctx.subject, ctx.record);
|
|
697
|
+
if (!shouldCreateSpan) {
|
|
698
|
+
injectContext(context.active(), ctx.headers, hdrsSetter);
|
|
699
|
+
return fn();
|
|
700
|
+
}
|
|
701
|
+
const tracer = getTracer();
|
|
702
|
+
const span = tracer.startSpan(`${SPAN_NAME_PUBLISH} ${ctx.subject}`, {
|
|
703
|
+
kind: SpanKind.PRODUCER,
|
|
704
|
+
attributes: {
|
|
705
|
+
...buildPublishAttributes({
|
|
706
|
+
subject: ctx.subject,
|
|
707
|
+
pattern: ctx.pattern,
|
|
708
|
+
serviceName: ctx.serviceName,
|
|
709
|
+
serverAddress: ctx.endpoint?.host,
|
|
710
|
+
serverPort: ctx.endpoint?.port,
|
|
711
|
+
kind: ctx.kind,
|
|
712
|
+
payloadBytes: ctx.payloadBytes,
|
|
713
|
+
messageId: ctx.messageId,
|
|
714
|
+
correlationId: ctx.correlationId
|
|
715
|
+
}),
|
|
716
|
+
...ctx.scheduleTarget ? { [ATTR_JETSTREAM_SCHEDULE_TARGET]: ctx.scheduleTarget } : {},
|
|
717
|
+
...captureMatchingHeaders(ctx.headers, config.captureHeaders),
|
|
718
|
+
...captureBodyAttribute(ctx.subject, ctx.payload, config.captureBody)
|
|
719
|
+
}
|
|
720
|
+
});
|
|
721
|
+
const ctxWithSpan = trace2.setSpan(context.active(), span);
|
|
722
|
+
injectContext(ctxWithSpan, ctx.headers, hdrsSetter);
|
|
723
|
+
const start = Date.now();
|
|
724
|
+
const invokeResponseHook = (error) => {
|
|
725
|
+
context.with(ctxWithSpan, () => {
|
|
726
|
+
safelyInvokeHook(HOOK_RESPONSE, config.responseHook, span, {
|
|
727
|
+
subject: ctx.subject,
|
|
728
|
+
durationMs: Date.now() - start,
|
|
729
|
+
error
|
|
730
|
+
});
|
|
731
|
+
});
|
|
732
|
+
};
|
|
733
|
+
try {
|
|
734
|
+
const result = await context.with(ctxWithSpan, async () => {
|
|
735
|
+
safelyInvokeHook(HOOK_PUBLISH, config.publishHook, span, {
|
|
736
|
+
subject: ctx.subject,
|
|
737
|
+
record: ctx.record,
|
|
738
|
+
kind: ctx.kind
|
|
739
|
+
});
|
|
740
|
+
return fn();
|
|
741
|
+
});
|
|
742
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
743
|
+
invokeResponseHook();
|
|
744
|
+
return result;
|
|
745
|
+
} catch (err) {
|
|
746
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
747
|
+
span.recordException(error);
|
|
748
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
|
|
749
|
+
invokeResponseHook(error);
|
|
750
|
+
throw err;
|
|
751
|
+
} finally {
|
|
752
|
+
span.end();
|
|
753
|
+
}
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
// src/otel/spans/consume.ts
|
|
757
|
+
import {
|
|
758
|
+
ROOT_CONTEXT,
|
|
759
|
+
SpanKind as SpanKind2,
|
|
760
|
+
SpanStatusCode as SpanStatusCode2,
|
|
761
|
+
context as context2,
|
|
762
|
+
trace as trace3
|
|
763
|
+
} from "@opentelemetry/api";
|
|
764
|
+
var isPromiseLike = (value) => typeof value === "object" && value !== null && typeof value.then === "function";
|
|
765
|
+
var applyExpectedError = (span, err) => {
|
|
766
|
+
span.setStatus({ code: SpanStatusCode2.OK });
|
|
767
|
+
applyExpectedErrorAttributes(span, err);
|
|
768
|
+
};
|
|
769
|
+
var applyUnexpectedError = (span, err) => {
|
|
770
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
771
|
+
span.recordException(error);
|
|
772
|
+
span.setStatus({ code: SpanStatusCode2.ERROR, message: error.message });
|
|
773
|
+
};
|
|
774
|
+
var withConsumeSpan = (ctx, config, fn, options = {}) => {
|
|
775
|
+
if (!config.enabled) return fn();
|
|
776
|
+
const parentCtx = extractContext(ROOT_CONTEXT, ctx.msg.headers, hdrsGetter);
|
|
777
|
+
const shouldCreateSpan = config.traces.has("consume" /* Consume */) && (config.shouldTraceConsume?.(ctx.subject, ctx.msg) ?? true);
|
|
778
|
+
if (!shouldCreateSpan) {
|
|
779
|
+
return context2.with(parentCtx, fn);
|
|
780
|
+
}
|
|
781
|
+
const tracer = getTracer();
|
|
782
|
+
const span = tracer.startSpan(
|
|
783
|
+
`${SPAN_NAME_PROCESS} ${ctx.subject}`,
|
|
784
|
+
{
|
|
785
|
+
kind: SpanKind2.CONSUMER,
|
|
786
|
+
attributes: {
|
|
787
|
+
...buildConsumeAttributes({
|
|
788
|
+
subject: ctx.subject,
|
|
789
|
+
pattern: ctx.pattern,
|
|
790
|
+
msg: ctx.msg,
|
|
791
|
+
info: ctx.info,
|
|
792
|
+
kind: ctx.kind,
|
|
793
|
+
payloadBytes: ctx.payloadBytes,
|
|
794
|
+
serviceName: ctx.serviceName,
|
|
795
|
+
serverAddress: ctx.endpoint?.host,
|
|
796
|
+
serverPort: ctx.endpoint?.port
|
|
797
|
+
}),
|
|
798
|
+
...captureMatchingHeaders(ctx.msg.headers, config.captureHeaders),
|
|
799
|
+
...captureBodyAttribute(ctx.subject, ctx.msg.data, config.captureBody)
|
|
800
|
+
}
|
|
801
|
+
},
|
|
802
|
+
parentCtx
|
|
803
|
+
);
|
|
804
|
+
const ctxWithSpan = trace3.setSpan(parentCtx, span);
|
|
805
|
+
const start = Date.now();
|
|
806
|
+
let finalized = false;
|
|
807
|
+
const { signal, timeoutLabel = "handler.timeout" } = options;
|
|
808
|
+
let detachAbort = null;
|
|
809
|
+
const invokeResponseHook = (durationMs, error) => {
|
|
810
|
+
context2.with(ctxWithSpan, () => {
|
|
811
|
+
safelyInvokeHook(HOOK_RESPONSE, config.responseHook, span, {
|
|
812
|
+
subject: ctx.subject,
|
|
813
|
+
durationMs,
|
|
814
|
+
error
|
|
815
|
+
});
|
|
816
|
+
});
|
|
817
|
+
};
|
|
818
|
+
const finishOk2 = () => {
|
|
819
|
+
if (finalized) return;
|
|
820
|
+
finalized = true;
|
|
821
|
+
detachAbort?.();
|
|
822
|
+
span.setStatus({ code: SpanStatusCode2.OK });
|
|
823
|
+
invokeResponseHook(Date.now() - start);
|
|
824
|
+
span.end();
|
|
825
|
+
};
|
|
826
|
+
const finishError2 = (err) => {
|
|
827
|
+
if (finalized) return;
|
|
828
|
+
finalized = true;
|
|
829
|
+
detachAbort?.();
|
|
830
|
+
let classification = "unexpected";
|
|
831
|
+
try {
|
|
832
|
+
classification = config.errorClassifier(err);
|
|
833
|
+
} catch {
|
|
834
|
+
}
|
|
835
|
+
if (classification === "expected") {
|
|
836
|
+
applyExpectedError(span, err);
|
|
837
|
+
} else {
|
|
838
|
+
applyUnexpectedError(span, err);
|
|
839
|
+
}
|
|
840
|
+
invokeResponseHook(Date.now() - start, err instanceof Error ? err : new Error(String(err)));
|
|
841
|
+
span.end();
|
|
842
|
+
};
|
|
843
|
+
const onAbort = () => {
|
|
844
|
+
if (finalized) return;
|
|
845
|
+
finalized = true;
|
|
846
|
+
const error = new Error(timeoutLabel);
|
|
847
|
+
span.addEvent(timeoutLabel);
|
|
848
|
+
span.recordException(error);
|
|
849
|
+
span.setStatus({ code: SpanStatusCode2.ERROR, message: timeoutLabel });
|
|
850
|
+
invokeResponseHook(Date.now() - start, error);
|
|
851
|
+
span.end();
|
|
852
|
+
};
|
|
853
|
+
if (signal) {
|
|
854
|
+
if (signal.aborted) {
|
|
855
|
+
onAbort();
|
|
856
|
+
} else {
|
|
857
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
858
|
+
detachAbort = () => {
|
|
859
|
+
signal.removeEventListener("abort", onAbort);
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
let result;
|
|
864
|
+
try {
|
|
865
|
+
result = context2.with(ctxWithSpan, () => {
|
|
866
|
+
safelyInvokeHook(HOOK_CONSUME, config.consumeHook, span, {
|
|
867
|
+
subject: ctx.subject,
|
|
868
|
+
msg: ctx.msg,
|
|
869
|
+
handlerMetadata: ctx.handlerMetadata,
|
|
870
|
+
kind: ctx.kind
|
|
871
|
+
});
|
|
872
|
+
return fn();
|
|
873
|
+
});
|
|
874
|
+
} catch (err) {
|
|
875
|
+
finishError2(err);
|
|
876
|
+
throw err;
|
|
877
|
+
}
|
|
878
|
+
if (isPromiseLike(result)) {
|
|
879
|
+
return Promise.resolve(result).then(
|
|
880
|
+
(value) => {
|
|
881
|
+
finishOk2();
|
|
882
|
+
return value;
|
|
883
|
+
},
|
|
884
|
+
(err) => {
|
|
885
|
+
finishError2(err);
|
|
886
|
+
throw err;
|
|
887
|
+
}
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
finishOk2();
|
|
891
|
+
return result;
|
|
892
|
+
};
|
|
893
|
+
|
|
894
|
+
// src/otel/spans/rpc-client.ts
|
|
895
|
+
import { Logger as Logger3 } from "@nestjs/common";
|
|
896
|
+
import { SpanKind as SpanKind3, SpanStatusCode as SpanStatusCode3, context as context3, trace as trace4 } from "@opentelemetry/api";
|
|
897
|
+
var logger3 = new Logger3("Jetstream:Otel");
|
|
898
|
+
var RPC_TIMEOUT_MESSAGE = "rpc.timeout";
|
|
899
|
+
var beginRpcClientSpan = (ctx, config) => {
|
|
900
|
+
if (!config.enabled) {
|
|
901
|
+
return {
|
|
902
|
+
activeContext: context3.active(),
|
|
903
|
+
finish: () => void 0
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
if (!config.traces.has("rpc.client.send" /* RpcClientSend */)) {
|
|
907
|
+
injectContext(context3.active(), ctx.headers, hdrsSetter);
|
|
908
|
+
return {
|
|
909
|
+
activeContext: context3.active(),
|
|
910
|
+
finish: () => void 0
|
|
911
|
+
};
|
|
912
|
+
}
|
|
913
|
+
const tracer = getTracer();
|
|
914
|
+
const span = tracer.startSpan(`${SPAN_NAME_SEND} ${ctx.subject}`, {
|
|
915
|
+
kind: SpanKind3.CLIENT,
|
|
916
|
+
attributes: {
|
|
917
|
+
...buildRpcClientAttributes({
|
|
918
|
+
subject: ctx.subject,
|
|
919
|
+
pattern: ctx.pattern,
|
|
920
|
+
correlationId: ctx.correlationId,
|
|
921
|
+
payloadBytes: ctx.payloadBytes,
|
|
922
|
+
messageId: ctx.messageId,
|
|
923
|
+
serviceName: ctx.serviceName,
|
|
924
|
+
serverAddress: ctx.endpoint?.host,
|
|
925
|
+
serverPort: ctx.endpoint?.port
|
|
926
|
+
}),
|
|
927
|
+
...captureMatchingHeaders(ctx.headers, config.captureHeaders),
|
|
928
|
+
...captureBodyAttribute(ctx.subject, ctx.payload, config.captureBody)
|
|
929
|
+
}
|
|
930
|
+
});
|
|
931
|
+
const ctxWithSpan = trace4.setSpan(context3.active(), span);
|
|
932
|
+
injectContext(ctxWithSpan, ctx.headers, hdrsSetter);
|
|
933
|
+
const start = Date.now();
|
|
934
|
+
let finalized = false;
|
|
935
|
+
const finish = (outcome) => {
|
|
936
|
+
if (finalized) return;
|
|
937
|
+
finalized = true;
|
|
938
|
+
let reply;
|
|
939
|
+
let error;
|
|
940
|
+
switch (outcome.kind) {
|
|
941
|
+
case "ok" /* Ok */:
|
|
942
|
+
reply = outcome.reply;
|
|
943
|
+
span.setStatus({ code: SpanStatusCode3.OK });
|
|
944
|
+
break;
|
|
945
|
+
case "reply-error" /* ReplyError */:
|
|
946
|
+
reply = outcome.replyPayload;
|
|
947
|
+
applyExpectedErrorAttributes(span, outcome.replyPayload);
|
|
948
|
+
span.setStatus({ code: SpanStatusCode3.OK });
|
|
949
|
+
break;
|
|
950
|
+
case "timeout" /* Timeout */:
|
|
951
|
+
error = new Error(RPC_TIMEOUT_MESSAGE);
|
|
952
|
+
span.addEvent(RPC_TIMEOUT_MESSAGE);
|
|
953
|
+
span.setStatus({ code: SpanStatusCode3.ERROR, message: RPC_TIMEOUT_MESSAGE });
|
|
954
|
+
break;
|
|
955
|
+
case "error" /* Error */:
|
|
956
|
+
error = outcome.error;
|
|
957
|
+
span.recordException(outcome.error);
|
|
958
|
+
span.setStatus({ code: SpanStatusCode3.ERROR, message: outcome.error.message });
|
|
959
|
+
break;
|
|
960
|
+
default: {
|
|
961
|
+
const unknownOutcome = outcome;
|
|
962
|
+
logger3.error(`Unhandled RPC outcome: ${String(unknownOutcome.kind)}`);
|
|
963
|
+
span.setStatus({ code: SpanStatusCode3.ERROR, message: "unknown outcome" });
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
context3.with(ctxWithSpan, () => {
|
|
967
|
+
safelyInvokeHook(HOOK_RESPONSE, config.responseHook, span, {
|
|
968
|
+
subject: ctx.subject,
|
|
969
|
+
durationMs: Date.now() - start,
|
|
970
|
+
reply,
|
|
971
|
+
error
|
|
972
|
+
});
|
|
973
|
+
});
|
|
974
|
+
span.end();
|
|
975
|
+
};
|
|
976
|
+
return { activeContext: ctxWithSpan, finish };
|
|
977
|
+
};
|
|
978
|
+
|
|
979
|
+
// src/otel/spans/dead-letter.ts
|
|
980
|
+
import { ROOT_CONTEXT as ROOT_CONTEXT2, SpanKind as SpanKind4, SpanStatusCode as SpanStatusCode4, context as context4, trace as trace5 } from "@opentelemetry/api";
|
|
981
|
+
var withDeadLetterSpan = async (ctx, config, fn) => {
|
|
982
|
+
if (!config.enabled || !config.traces.has("dead_letter" /* DeadLetter */)) {
|
|
983
|
+
return fn();
|
|
984
|
+
}
|
|
985
|
+
const parentCtx = extractContext(ROOT_CONTEXT2, ctx.msg.headers, hdrsGetter);
|
|
986
|
+
const tracer = getTracer();
|
|
987
|
+
const span = tracer.startSpan(
|
|
988
|
+
`${SPAN_NAME_DEAD_LETTER} ${ctx.msg.subject}`,
|
|
989
|
+
{
|
|
990
|
+
kind: SpanKind4.INTERNAL,
|
|
991
|
+
attributes: buildDeadLetterAttributes({
|
|
992
|
+
subject: ctx.msg.subject,
|
|
993
|
+
pattern: ctx.pattern,
|
|
994
|
+
serviceName: ctx.serviceName,
|
|
995
|
+
serverAddress: ctx.endpoint?.host,
|
|
996
|
+
serverPort: ctx.endpoint?.port,
|
|
997
|
+
finalDeliveryCount: ctx.finalDeliveryCount,
|
|
998
|
+
reason: ctx.reason
|
|
999
|
+
})
|
|
1000
|
+
},
|
|
1001
|
+
parentCtx
|
|
1002
|
+
);
|
|
1003
|
+
const ctxWithSpan = trace5.setSpan(parentCtx, span);
|
|
1004
|
+
const start = Date.now();
|
|
1005
|
+
const invokeResponseHook = (error) => {
|
|
1006
|
+
context4.with(ctxWithSpan, () => {
|
|
1007
|
+
safelyInvokeHook(HOOK_RESPONSE, config.responseHook, span, {
|
|
1008
|
+
subject: ctx.msg.subject,
|
|
1009
|
+
durationMs: Date.now() - start,
|
|
1010
|
+
error
|
|
1011
|
+
});
|
|
1012
|
+
});
|
|
1013
|
+
};
|
|
1014
|
+
try {
|
|
1015
|
+
const result = await context4.with(ctxWithSpan, fn);
|
|
1016
|
+
span.setStatus({ code: SpanStatusCode4.OK });
|
|
1017
|
+
invokeResponseHook();
|
|
1018
|
+
return result;
|
|
1019
|
+
} catch (err) {
|
|
1020
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
1021
|
+
span.recordException(error);
|
|
1022
|
+
span.setStatus({ code: SpanStatusCode4.ERROR, message: error.message });
|
|
1023
|
+
invokeResponseHook(error);
|
|
1024
|
+
throw err;
|
|
1025
|
+
} finally {
|
|
1026
|
+
span.end();
|
|
1027
|
+
}
|
|
1028
|
+
};
|
|
1029
|
+
|
|
1030
|
+
// src/otel/spans/infrastructure.ts
|
|
1031
|
+
import { Logger as Logger4 } from "@nestjs/common";
|
|
1032
|
+
import {
|
|
1033
|
+
SpanKind as SpanKind5,
|
|
1034
|
+
SpanStatusCode as SpanStatusCode5,
|
|
1035
|
+
context as context5,
|
|
1036
|
+
trace as trace6
|
|
1037
|
+
} from "@opentelemetry/api";
|
|
1038
|
+
var logger4 = new Logger4("Jetstream:Otel");
|
|
1039
|
+
var startInfraSpan = (config, traceKind, name, ctx, extraAttributes = {}) => {
|
|
1040
|
+
if (!config.enabled || !config.traces.has(traceKind)) return null;
|
|
1041
|
+
const tracer = getTracer();
|
|
1042
|
+
const attributes = {
|
|
1043
|
+
[ATTR_JETSTREAM_SERVICE_NAME]: ctx.serviceName
|
|
1044
|
+
};
|
|
1045
|
+
if (ctx.endpoint?.host) attributes[ATTR_SERVER_ADDRESS] = ctx.endpoint.host;
|
|
1046
|
+
if (ctx.endpoint?.port !== void 0) attributes[ATTR_SERVER_PORT] = ctx.endpoint.port;
|
|
1047
|
+
for (const [key, value] of Object.entries(extraAttributes)) {
|
|
1048
|
+
if (value !== void 0) attributes[key] = value;
|
|
1049
|
+
}
|
|
1050
|
+
return tracer.startSpan(name, { kind: SpanKind5.INTERNAL, attributes });
|
|
1051
|
+
};
|
|
1052
|
+
var finishOk = (span) => {
|
|
1053
|
+
span.setStatus({ code: SpanStatusCode5.OK });
|
|
1054
|
+
span.end();
|
|
1055
|
+
};
|
|
1056
|
+
var finishError = (span, err) => {
|
|
1057
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
1058
|
+
span.recordException(error);
|
|
1059
|
+
span.setStatus({ code: SpanStatusCode5.ERROR, message: error.message });
|
|
1060
|
+
span.end();
|
|
1061
|
+
};
|
|
1062
|
+
var wrapInfra = async (config, traceKind, name, ctx, attributes, op) => {
|
|
1063
|
+
const span = startInfraSpan(config, traceKind, name, ctx, attributes);
|
|
1064
|
+
if (!span) return op();
|
|
1065
|
+
const ctxWithSpan = trace6.setSpan(context5.active(), span);
|
|
1066
|
+
try {
|
|
1067
|
+
const result = await context5.with(ctxWithSpan, op);
|
|
1068
|
+
finishOk(span);
|
|
1069
|
+
return result;
|
|
1070
|
+
} catch (err) {
|
|
1071
|
+
finishError(span, err);
|
|
1072
|
+
throw err;
|
|
1073
|
+
}
|
|
1074
|
+
};
|
|
1075
|
+
var beginConnectionLifecycleSpan = (config, ctx) => {
|
|
1076
|
+
const span = startInfraSpan(
|
|
1077
|
+
config,
|
|
1078
|
+
"connection.lifecycle" /* ConnectionLifecycle */,
|
|
1079
|
+
SPAN_NAME_NATS_CONNECTION,
|
|
1080
|
+
ctx,
|
|
1081
|
+
{ [ATTR_NATS_CONNECTION_SERVER]: ctx.server }
|
|
1082
|
+
);
|
|
1083
|
+
if (!span) {
|
|
1084
|
+
return {
|
|
1085
|
+
recordEvent: () => void 0,
|
|
1086
|
+
finish: () => void 0
|
|
1087
|
+
};
|
|
1088
|
+
}
|
|
1089
|
+
let finalized = false;
|
|
1090
|
+
return {
|
|
1091
|
+
recordEvent: (name, attributes) => {
|
|
1092
|
+
if (finalized) {
|
|
1093
|
+
logger4.debug(`recordEvent('${name}') called after connection span finished`);
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
span.addEvent(name, attributes);
|
|
1097
|
+
},
|
|
1098
|
+
finish: (err) => {
|
|
1099
|
+
if (finalized) return;
|
|
1100
|
+
finalized = true;
|
|
1101
|
+
if (err === void 0) finishOk(span);
|
|
1102
|
+
else finishError(span, err);
|
|
1103
|
+
}
|
|
1104
|
+
};
|
|
1105
|
+
};
|
|
1106
|
+
var withSelfHealingSpan = (config, ctx, op) => wrapInfra(
|
|
1107
|
+
config,
|
|
1108
|
+
"self_healing" /* SelfHealing */,
|
|
1109
|
+
SPAN_NAME_JETSTREAM_SELF_HEALING,
|
|
1110
|
+
ctx,
|
|
1111
|
+
{
|
|
1112
|
+
[ATTR_MESSAGING_NATS_STREAM_NAME]: ctx.stream,
|
|
1113
|
+
[ATTR_MESSAGING_CONSUMER_GROUP_NAME]: ctx.consumer,
|
|
1114
|
+
[ATTR_JETSTREAM_SELF_HEALING_REASON]: ctx.reason
|
|
1115
|
+
},
|
|
1116
|
+
op
|
|
1117
|
+
);
|
|
1118
|
+
var withProvisioningSpan = (config, ctx, op) => wrapInfra(
|
|
1119
|
+
config,
|
|
1120
|
+
"provisioning" /* Provisioning */,
|
|
1121
|
+
`${SPAN_NAME_JETSTREAM_PROVISIONING_PREFIX}${ctx.entity}`,
|
|
1122
|
+
ctx,
|
|
1123
|
+
{
|
|
1124
|
+
[ATTR_JETSTREAM_PROVISIONING_ENTITY]: ctx.entity,
|
|
1125
|
+
[ATTR_JETSTREAM_PROVISIONING_ACTION]: ctx.action,
|
|
1126
|
+
[ATTR_JETSTREAM_PROVISIONING_NAME]: ctx.name
|
|
1127
|
+
},
|
|
1128
|
+
op
|
|
1129
|
+
);
|
|
1130
|
+
var withMigrationSpan = (config, ctx, op) => wrapInfra(
|
|
1131
|
+
config,
|
|
1132
|
+
"migration" /* Migration */,
|
|
1133
|
+
SPAN_NAME_JETSTREAM_MIGRATION,
|
|
1134
|
+
ctx,
|
|
1135
|
+
{
|
|
1136
|
+
[ATTR_MESSAGING_NATS_STREAM_NAME]: ctx.stream,
|
|
1137
|
+
[ATTR_JETSTREAM_MIGRATION_REASON]: ctx.reason
|
|
1138
|
+
},
|
|
1139
|
+
op
|
|
1140
|
+
);
|
|
1141
|
+
var withShutdownSpan = (config, ctx, op) => wrapInfra(config, "shutdown" /* Shutdown */, SPAN_NAME_JETSTREAM_SHUTDOWN, ctx, {}, op);
|
|
1142
|
+
|
|
227
1143
|
// src/client/jetstream.record.ts
|
|
228
1144
|
var JetstreamRecord = class {
|
|
229
1145
|
constructor(data, headers2, timeout, messageId, schedule, ttl) {
|
|
@@ -376,9 +1292,14 @@ var JetstreamRecordBuilder = class {
|
|
|
376
1292
|
this.ttlDuration
|
|
377
1293
|
);
|
|
378
1294
|
}
|
|
379
|
-
/**
|
|
1295
|
+
/**
|
|
1296
|
+
* Validate that a header key is not reserved. NATS treats header names
|
|
1297
|
+
* case-insensitively, so the check is against the lowercase form to keep
|
|
1298
|
+
* `'X-Correlation-ID'`, `'x-correlation-id'`, and any other casing in
|
|
1299
|
+
* lockstep. `RESERVED_HEADERS` is defined as an all-lowercase set.
|
|
1300
|
+
*/
|
|
380
1301
|
validateHeaderKey(key) {
|
|
381
|
-
if (RESERVED_HEADERS.has(key)) {
|
|
1302
|
+
if (RESERVED_HEADERS.has(key.toLowerCase())) {
|
|
382
1303
|
throw new Error(
|
|
383
1304
|
`Header "${key}" is reserved by the JetStream transport and cannot be set manually. Reserved headers: ${[...RESERVED_HEADERS].join(", ")}`
|
|
384
1305
|
);
|
|
@@ -399,6 +1320,11 @@ var nanosToGoDuration = (nanos) => {
|
|
|
399
1320
|
|
|
400
1321
|
// src/client/jetstream.client.ts
|
|
401
1322
|
var BROADCAST_SUBJECT_PREFIX = "broadcast.";
|
|
1323
|
+
var detectEventKind = (pattern) => {
|
|
1324
|
+
if (pattern.startsWith("broadcast:" /* Broadcast */)) return "broadcast" /* Broadcast */;
|
|
1325
|
+
if (pattern.startsWith("ordered:" /* Ordered */)) return "ordered" /* Ordered */;
|
|
1326
|
+
return "event" /* Event */;
|
|
1327
|
+
};
|
|
402
1328
|
var JetstreamClient = class extends ClientProxy {
|
|
403
1329
|
constructor(rootOptions, targetServiceName, connection, codec, eventBus) {
|
|
404
1330
|
super();
|
|
@@ -414,8 +1340,11 @@ var JetstreamClient = class extends ClientProxy {
|
|
|
414
1340
|
this.orderedSubjectPrefix = `${targetInternal}.${"ordered" /* Ordered */}.`;
|
|
415
1341
|
this.isCoreMode = isCoreRpcMode(this.rootOptions.rpc);
|
|
416
1342
|
this.defaultRpcTimeout = isJetStreamRpcMode(this.rootOptions.rpc) ? this.rootOptions.rpc?.timeout ?? DEFAULT_JETSTREAM_RPC_TIMEOUT : this.rootOptions.rpc?.timeout ?? DEFAULT_RPC_TIMEOUT;
|
|
1343
|
+
const derived = deriveOtelAttrs(this.rootOptions);
|
|
1344
|
+
this.otel = derived.otel;
|
|
1345
|
+
this.serverEndpoint = derived.serverEndpoint;
|
|
417
1346
|
}
|
|
418
|
-
logger = new
|
|
1347
|
+
logger = new Logger5("Jetstream:Client");
|
|
419
1348
|
/** Target service name this client sends messages to. */
|
|
420
1349
|
targetName;
|
|
421
1350
|
/** Pre-cached caller name derived from rootOptions.name, computed once in constructor. */
|
|
@@ -435,6 +1364,10 @@ var JetstreamClient = class extends ClientProxy {
|
|
|
435
1364
|
*/
|
|
436
1365
|
isCoreMode;
|
|
437
1366
|
defaultRpcTimeout;
|
|
1367
|
+
/** Resolved OpenTelemetry configuration, computed once in the constructor. */
|
|
1368
|
+
otel;
|
|
1369
|
+
/** Server endpoint parts used for `server.address` / `server.port` span attributes. */
|
|
1370
|
+
serverEndpoint;
|
|
438
1371
|
/** Shared inbox for JetStream-mode RPC responses. */
|
|
439
1372
|
inbox = null;
|
|
440
1373
|
inboxSubscription = null;
|
|
@@ -502,33 +1435,55 @@ var JetstreamClient = class extends ClientProxy {
|
|
|
502
1435
|
if (!this.readyForPublish) await this.connect();
|
|
503
1436
|
const { data, hdrs, messageId, schedule, ttl } = this.extractRecordData(packet.data);
|
|
504
1437
|
const eventSubject = this.buildEventSubject(packet.pattern);
|
|
1438
|
+
const publishSubject = schedule ? this.buildScheduleSubject(eventSubject) : eventSubject;
|
|
505
1439
|
const msgHeaders = this.buildHeaders(hdrs, { subject: eventSubject });
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
1440
|
+
const encoded = this.codec.encode(data);
|
|
1441
|
+
const effectiveMsgId = messageId ?? nuid.next();
|
|
1442
|
+
const record = packet.data instanceof JetstreamRecord ? packet.data : new JetstreamRecord(data, /* @__PURE__ */ new Map());
|
|
1443
|
+
await withPublishSpan(
|
|
1444
|
+
{
|
|
1445
|
+
subject: publishSubject,
|
|
1446
|
+
pattern: packet.pattern,
|
|
1447
|
+
record,
|
|
1448
|
+
kind: detectEventKind(packet.pattern),
|
|
1449
|
+
payloadBytes: encoded.length,
|
|
1450
|
+
payload: encoded,
|
|
1451
|
+
messageId: effectiveMsgId,
|
|
509
1452
|
headers: msgHeaders,
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
schedule:
|
|
513
|
-
|
|
514
|
-
|
|
1453
|
+
serviceName: this.callerName,
|
|
1454
|
+
endpoint: this.serverEndpoint,
|
|
1455
|
+
scheduleTarget: schedule ? eventSubject : void 0
|
|
1456
|
+
},
|
|
1457
|
+
this.otel,
|
|
1458
|
+
async () => {
|
|
1459
|
+
const warnIfDuplicate = (kindLabel, ack2) => {
|
|
1460
|
+
if (ack2.duplicate) {
|
|
1461
|
+
this.logger.warn(
|
|
1462
|
+
`Duplicate ${kindLabel} publish detected: ${publishSubject} (seq: ${ack2.seq})`
|
|
1463
|
+
);
|
|
1464
|
+
}
|
|
1465
|
+
};
|
|
1466
|
+
if (schedule) {
|
|
1467
|
+
const ack2 = await this.connection.getJetStreamClient().publish(publishSubject, encoded, {
|
|
1468
|
+
headers: msgHeaders,
|
|
1469
|
+
msgID: effectiveMsgId,
|
|
1470
|
+
ttl,
|
|
1471
|
+
schedule: {
|
|
1472
|
+
specification: schedule.at,
|
|
1473
|
+
target: eventSubject
|
|
1474
|
+
}
|
|
1475
|
+
});
|
|
1476
|
+
warnIfDuplicate("scheduled", ack2);
|
|
1477
|
+
return;
|
|
515
1478
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
);
|
|
521
|
-
|
|
522
|
-
} else {
|
|
523
|
-
const ack = await this.connection.getJetStreamClient().publish(eventSubject, this.codec.encode(data), {
|
|
524
|
-
headers: msgHeaders,
|
|
525
|
-
msgID: messageId ?? nuid.next(),
|
|
526
|
-
ttl
|
|
527
|
-
});
|
|
528
|
-
if (ack.duplicate) {
|
|
529
|
-
this.logger.warn(`Duplicate event publish detected: ${eventSubject} (seq: ${ack.seq})`);
|
|
1479
|
+
const ack = await this.connection.getJetStreamClient().publish(publishSubject, encoded, {
|
|
1480
|
+
headers: msgHeaders,
|
|
1481
|
+
msgID: effectiveMsgId,
|
|
1482
|
+
ttl
|
|
1483
|
+
});
|
|
1484
|
+
warnIfDuplicate("event", ack);
|
|
530
1485
|
}
|
|
531
|
-
|
|
1486
|
+
);
|
|
532
1487
|
return void 0;
|
|
533
1488
|
}
|
|
534
1489
|
/**
|
|
@@ -579,24 +1534,46 @@ var JetstreamClient = class extends ClientProxy {
|
|
|
579
1534
|
}
|
|
580
1535
|
/** Core mode: nc.request() with timeout. */
|
|
581
1536
|
async publishCoreRpc(subject, data, customHeaders, timeout, callback) {
|
|
1537
|
+
const effectiveTimeout = timeout ?? this.defaultRpcTimeout;
|
|
1538
|
+
const hdrs = this.buildHeaders(customHeaders, { subject });
|
|
1539
|
+
const encoded = this.codec.encode(data);
|
|
1540
|
+
const spanHandle = beginRpcClientSpan(
|
|
1541
|
+
{
|
|
1542
|
+
subject,
|
|
1543
|
+
payloadBytes: encoded.length,
|
|
1544
|
+
payload: encoded,
|
|
1545
|
+
headers: hdrs,
|
|
1546
|
+
serviceName: this.callerName,
|
|
1547
|
+
endpoint: this.serverEndpoint
|
|
1548
|
+
},
|
|
1549
|
+
this.otel
|
|
1550
|
+
);
|
|
582
1551
|
try {
|
|
583
1552
|
const nc = this.readyForPublish ? this.connection.unwrap : await this.connect();
|
|
584
|
-
const
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
1553
|
+
const response = await context6.with(
|
|
1554
|
+
spanHandle.activeContext,
|
|
1555
|
+
() => nc.request(subject, encoded, {
|
|
1556
|
+
timeout: effectiveTimeout,
|
|
1557
|
+
headers: hdrs
|
|
1558
|
+
})
|
|
1559
|
+
);
|
|
590
1560
|
const decoded = this.codec.decode(response.data);
|
|
591
1561
|
if (response.headers?.get("x-error" /* Error */)) {
|
|
1562
|
+
spanHandle.finish({ kind: "reply-error" /* ReplyError */, replyPayload: decoded });
|
|
592
1563
|
callback({ err: decoded, response: null, isDisposed: true });
|
|
593
1564
|
} else {
|
|
1565
|
+
spanHandle.finish({ kind: "ok" /* Ok */, reply: decoded });
|
|
594
1566
|
callback({ err: null, response: decoded, isDisposed: true });
|
|
595
1567
|
}
|
|
596
1568
|
} catch (err) {
|
|
597
1569
|
const error = err instanceof Error ? err : new Error("Unknown error");
|
|
598
|
-
|
|
599
|
-
|
|
1570
|
+
if (error instanceof TimeoutError) {
|
|
1571
|
+
spanHandle.finish({ kind: "timeout" /* Timeout */ });
|
|
1572
|
+
this.eventBus.emit("rpcTimeout" /* RpcTimeout */, subject, "");
|
|
1573
|
+
} else {
|
|
1574
|
+
spanHandle.finish({ kind: "error" /* Error */, error });
|
|
1575
|
+
this.eventBus.emit("error" /* Error */, error, "client-rpc");
|
|
1576
|
+
}
|
|
600
1577
|
callback({ err: error, response: null, isDisposed: true });
|
|
601
1578
|
}
|
|
602
1579
|
}
|
|
@@ -604,12 +1581,55 @@ var JetstreamClient = class extends ClientProxy {
|
|
|
604
1581
|
async publishJetStreamRpc(subject, data, callback, options) {
|
|
605
1582
|
const { headers: customHeaders, correlationId, messageId } = options;
|
|
606
1583
|
const effectiveTimeout = options.timeout ?? this.defaultRpcTimeout;
|
|
607
|
-
this.
|
|
1584
|
+
const hdrs = this.buildHeaders(customHeaders, {
|
|
1585
|
+
subject,
|
|
1586
|
+
correlationId,
|
|
1587
|
+
replyTo: this.inbox ?? ""
|
|
1588
|
+
});
|
|
1589
|
+
const encoded = this.codec.encode(data);
|
|
1590
|
+
const spanHandle = beginRpcClientSpan(
|
|
1591
|
+
{
|
|
1592
|
+
subject,
|
|
1593
|
+
correlationId,
|
|
1594
|
+
payloadBytes: encoded.length,
|
|
1595
|
+
payload: encoded,
|
|
1596
|
+
messageId,
|
|
1597
|
+
headers: hdrs,
|
|
1598
|
+
serviceName: this.callerName,
|
|
1599
|
+
endpoint: this.serverEndpoint
|
|
1600
|
+
},
|
|
1601
|
+
this.otel
|
|
1602
|
+
);
|
|
1603
|
+
this.pendingMessages.set(correlationId, (packet) => {
|
|
1604
|
+
if (packet.err) {
|
|
1605
|
+
if (packet.err instanceof Error) {
|
|
1606
|
+
spanHandle.finish({ kind: "error" /* Error */, error: packet.err });
|
|
1607
|
+
} else {
|
|
1608
|
+
spanHandle.finish({ kind: "reply-error" /* ReplyError */, replyPayload: packet.err });
|
|
1609
|
+
}
|
|
1610
|
+
} else {
|
|
1611
|
+
spanHandle.finish({ kind: "ok" /* Ok */, reply: packet.response });
|
|
1612
|
+
}
|
|
1613
|
+
callback(packet);
|
|
1614
|
+
});
|
|
1615
|
+
const timeoutId = setTimeout(() => {
|
|
1616
|
+
if (!this.pendingMessages.has(correlationId)) return;
|
|
1617
|
+
this.pendingTimeouts.delete(correlationId);
|
|
1618
|
+
this.pendingMessages.delete(correlationId);
|
|
1619
|
+
spanHandle.finish({ kind: "timeout" /* Timeout */ });
|
|
1620
|
+
this.eventBus.emit("rpcTimeout" /* RpcTimeout */, subject, correlationId);
|
|
1621
|
+
callback({ err: new Error(RPC_TIMEOUT_MESSAGE), response: null, isDisposed: true });
|
|
1622
|
+
}, effectiveTimeout);
|
|
1623
|
+
this.pendingTimeouts.set(correlationId, timeoutId);
|
|
608
1624
|
try {
|
|
609
1625
|
if (!this.readyForPublish) await this.connect();
|
|
610
1626
|
if (!this.pendingMessages.has(correlationId)) return;
|
|
611
1627
|
if (!this.inbox) {
|
|
1628
|
+
clearTimeout(timeoutId);
|
|
1629
|
+
this.pendingTimeouts.delete(correlationId);
|
|
612
1630
|
this.pendingMessages.delete(correlationId);
|
|
1631
|
+
const inboxError = new Error("Inbox not initialized");
|
|
1632
|
+
spanHandle.finish({ kind: "error" /* Error */, error: inboxError });
|
|
613
1633
|
callback({
|
|
614
1634
|
err: new Error("Inbox not initialized \u2014 JetStream RPC mode requires a connected inbox"),
|
|
615
1635
|
response: null,
|
|
@@ -617,24 +1637,13 @@ var JetstreamClient = class extends ClientProxy {
|
|
|
617
1637
|
});
|
|
618
1638
|
return;
|
|
619
1639
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
this.
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
}, effectiveTimeout);
|
|
628
|
-
this.pendingTimeouts.set(correlationId, timeoutId);
|
|
629
|
-
const hdrs = this.buildHeaders(customHeaders, {
|
|
630
|
-
subject,
|
|
631
|
-
correlationId,
|
|
632
|
-
replyTo: this.inbox
|
|
633
|
-
});
|
|
634
|
-
await this.connection.getJetStreamClient().publish(subject, this.codec.encode(data), {
|
|
635
|
-
headers: hdrs,
|
|
636
|
-
msgID: messageId ?? nuid.next()
|
|
637
|
-
});
|
|
1640
|
+
await context6.with(
|
|
1641
|
+
spanHandle.activeContext,
|
|
1642
|
+
() => this.connection.getJetStreamClient().publish(subject, encoded, {
|
|
1643
|
+
headers: hdrs,
|
|
1644
|
+
msgID: messageId ?? nuid.next()
|
|
1645
|
+
})
|
|
1646
|
+
);
|
|
638
1647
|
} catch (err) {
|
|
639
1648
|
const existingTimeout = this.pendingTimeouts.get(correlationId);
|
|
640
1649
|
if (existingTimeout) {
|
|
@@ -644,7 +1653,8 @@ var JetstreamClient = class extends ClientProxy {
|
|
|
644
1653
|
if (!this.pendingMessages.has(correlationId)) return;
|
|
645
1654
|
this.pendingMessages.delete(correlationId);
|
|
646
1655
|
const error = err instanceof Error ? err : new Error("Unknown error");
|
|
647
|
-
|
|
1656
|
+
spanHandle.finish({ kind: "error" /* Error */, error });
|
|
1657
|
+
this.eventBus.emit("error" /* Error */, error, `jetstream-rpc-publish:${subject}`);
|
|
648
1658
|
callback({ err: error, response: null, isDisposed: true });
|
|
649
1659
|
}
|
|
650
1660
|
}
|
|
@@ -827,7 +1837,7 @@ var MsgpackCodec = class {
|
|
|
827
1837
|
};
|
|
828
1838
|
|
|
829
1839
|
// src/connection/connection.provider.ts
|
|
830
|
-
import { Logger as
|
|
1840
|
+
import { Logger as Logger6 } from "@nestjs/common";
|
|
831
1841
|
import {
|
|
832
1842
|
connect
|
|
833
1843
|
} from "@nats-io/transport-node";
|
|
@@ -844,6 +1854,10 @@ var ConnectionProvider = class {
|
|
|
844
1854
|
constructor(options, eventBus) {
|
|
845
1855
|
this.options = options;
|
|
846
1856
|
this.eventBus = eventBus;
|
|
1857
|
+
const derived = deriveOtelAttrs(options);
|
|
1858
|
+
this.otel = derived.otel;
|
|
1859
|
+
this.otelServiceName = derived.serviceName;
|
|
1860
|
+
this.otelEndpoint = derived.serverEndpoint;
|
|
847
1861
|
this.nc$ = defer(() => this.getConnection()).pipe(
|
|
848
1862
|
shareReplay({ bufferSize: 1, refCount: false })
|
|
849
1863
|
);
|
|
@@ -856,12 +1870,16 @@ var ConnectionProvider = class {
|
|
|
856
1870
|
nc$;
|
|
857
1871
|
/** Live stream of connection status events (no replay). */
|
|
858
1872
|
status$;
|
|
859
|
-
logger = new
|
|
1873
|
+
logger = new Logger6("Jetstream:Connection");
|
|
860
1874
|
connection = null;
|
|
861
1875
|
connectionPromise = null;
|
|
862
1876
|
jsClient = null;
|
|
863
1877
|
jsmInstance = null;
|
|
864
1878
|
jsmPromise = null;
|
|
1879
|
+
otel;
|
|
1880
|
+
otelServiceName;
|
|
1881
|
+
otelEndpoint;
|
|
1882
|
+
lifecycleSpan = null;
|
|
865
1883
|
/**
|
|
866
1884
|
* Establish NATS connection. Idempotent — returns cached connection on subsequent calls.
|
|
867
1885
|
*
|
|
@@ -925,14 +1943,24 @@ var ConnectionProvider = class {
|
|
|
925
1943
|
}
|
|
926
1944
|
if (!this.connection || this.connection.isClosed()) return;
|
|
927
1945
|
try {
|
|
928
|
-
await
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
1946
|
+
await withShutdownSpan(
|
|
1947
|
+
this.otel,
|
|
1948
|
+
{ serviceName: this.otelServiceName, endpoint: this.otelEndpoint },
|
|
1949
|
+
async () => {
|
|
1950
|
+
try {
|
|
1951
|
+
await this.connection?.drain();
|
|
1952
|
+
await this.connection?.closed();
|
|
1953
|
+
} catch {
|
|
1954
|
+
try {
|
|
1955
|
+
await this.connection?.close();
|
|
1956
|
+
} catch {
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
);
|
|
935
1961
|
} finally {
|
|
1962
|
+
this.lifecycleSpan?.finish();
|
|
1963
|
+
this.lifecycleSpan = null;
|
|
936
1964
|
this.connection = null;
|
|
937
1965
|
this.connectionPromise = null;
|
|
938
1966
|
this.jsClient = null;
|
|
@@ -952,17 +1980,25 @@ var ConnectionProvider = class {
|
|
|
952
1980
|
}
|
|
953
1981
|
/** Internal: establish the physical connection with reconnect monitoring. */
|
|
954
1982
|
async establish() {
|
|
955
|
-
const name = internalName(this.options.name);
|
|
956
1983
|
try {
|
|
957
1984
|
const nc = await connect({
|
|
958
1985
|
...DEFAULT_OPTIONS,
|
|
1986
|
+
// Default the NATS connection name to the OTel-derived service name so
|
|
1987
|
+
// `nats server info` lines up with span attributes, but let user-supplied
|
|
1988
|
+
// `connectionOptions.name` win when set.
|
|
1989
|
+
name: this.otelServiceName,
|
|
959
1990
|
...this.options.connectionOptions,
|
|
960
|
-
servers: this.options.servers
|
|
961
|
-
name
|
|
1991
|
+
servers: this.options.servers
|
|
962
1992
|
});
|
|
963
1993
|
this.connection = nc;
|
|
964
1994
|
this.logger.log(`NATS connection established: ${nc.getServer()}`);
|
|
965
1995
|
this.eventBus.emit("connect" /* Connect */, nc.getServer());
|
|
1996
|
+
this.lifecycleSpan?.finish();
|
|
1997
|
+
this.lifecycleSpan = beginConnectionLifecycleSpan(this.otel, {
|
|
1998
|
+
serviceName: this.otelServiceName,
|
|
1999
|
+
endpoint: this.otelEndpoint,
|
|
2000
|
+
server: nc.getServer()
|
|
2001
|
+
});
|
|
966
2002
|
this.monitorStatus(nc);
|
|
967
2003
|
return nc;
|
|
968
2004
|
} catch (err) {
|
|
@@ -972,37 +2008,55 @@ var ConnectionProvider = class {
|
|
|
972
2008
|
throw err;
|
|
973
2009
|
}
|
|
974
2010
|
}
|
|
2011
|
+
/** Handle a single `nc.status()` event, emitting hooks and span events. */
|
|
2012
|
+
handleStatusEvent(status, nc) {
|
|
2013
|
+
switch (status.type) {
|
|
2014
|
+
case "disconnect":
|
|
2015
|
+
this.eventBus.emit("disconnect" /* Disconnect */);
|
|
2016
|
+
this.lifecycleSpan?.recordEvent(EVENT_CONNECTION_DISCONNECTED);
|
|
2017
|
+
break;
|
|
2018
|
+
case "reconnect":
|
|
2019
|
+
this.jsClient = null;
|
|
2020
|
+
this.jsmInstance = null;
|
|
2021
|
+
this.jsmPromise = null;
|
|
2022
|
+
this.eventBus.emit("reconnect" /* Reconnect */, nc.getServer());
|
|
2023
|
+
this.lifecycleSpan?.recordEvent(EVENT_CONNECTION_RECONNECTED, {
|
|
2024
|
+
[ATTR_NATS_CONNECTION_SERVER]: nc.getServer()
|
|
2025
|
+
});
|
|
2026
|
+
break;
|
|
2027
|
+
case "error":
|
|
2028
|
+
this.eventBus.emit(
|
|
2029
|
+
"error" /* Error */,
|
|
2030
|
+
status.error,
|
|
2031
|
+
"connection"
|
|
2032
|
+
);
|
|
2033
|
+
break;
|
|
2034
|
+
case "update":
|
|
2035
|
+
case "ldm":
|
|
2036
|
+
case "reconnecting":
|
|
2037
|
+
case "ping":
|
|
2038
|
+
case "staleConnection":
|
|
2039
|
+
case "forceReconnect":
|
|
2040
|
+
case "slowConsumer":
|
|
2041
|
+
case "close":
|
|
2042
|
+
break;
|
|
2043
|
+
default: {
|
|
2044
|
+
const _exhaustive = status;
|
|
2045
|
+
const unknown = _exhaustive.type ?? "unknown";
|
|
2046
|
+
this.logger.warn(`Unhandled NATS status event: ${unknown}`);
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
975
2050
|
/** Subscribe to connection status events and emit hooks. */
|
|
976
2051
|
monitorStatus(nc) {
|
|
977
2052
|
void (async () => {
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
this.eventBus.emit("disconnect" /* Disconnect */);
|
|
982
|
-
break;
|
|
983
|
-
case "reconnect":
|
|
984
|
-
this.jsClient = null;
|
|
985
|
-
this.jsmInstance = null;
|
|
986
|
-
this.jsmPromise = null;
|
|
987
|
-
this.eventBus.emit("reconnect" /* Reconnect */, nc.getServer());
|
|
988
|
-
break;
|
|
989
|
-
case "error":
|
|
990
|
-
this.eventBus.emit(
|
|
991
|
-
"error" /* Error */,
|
|
992
|
-
status.error,
|
|
993
|
-
"connection"
|
|
994
|
-
);
|
|
995
|
-
break;
|
|
996
|
-
case "update":
|
|
997
|
-
case "ldm":
|
|
998
|
-
case "reconnecting":
|
|
999
|
-
case "ping":
|
|
1000
|
-
case "staleConnection":
|
|
1001
|
-
case "forceReconnect":
|
|
1002
|
-
case "slowConsumer":
|
|
1003
|
-
case "close":
|
|
1004
|
-
break;
|
|
2053
|
+
try {
|
|
2054
|
+
for await (const status of nc.status()) {
|
|
2055
|
+
this.handleStatusEvent(status, nc);
|
|
1005
2056
|
}
|
|
2057
|
+
} finally {
|
|
2058
|
+
this.lifecycleSpan?.finish();
|
|
2059
|
+
this.lifecycleSpan = null;
|
|
1006
2060
|
}
|
|
1007
2061
|
})().catch((err) => {
|
|
1008
2062
|
this.logger.error("Status monitor error", err);
|
|
@@ -1014,8 +2068,8 @@ var ConnectionProvider = class {
|
|
|
1014
2068
|
var EventBus = class {
|
|
1015
2069
|
hooks;
|
|
1016
2070
|
logger;
|
|
1017
|
-
constructor(
|
|
1018
|
-
this.logger =
|
|
2071
|
+
constructor(logger5, hooks) {
|
|
2072
|
+
this.logger = logger5;
|
|
1019
2073
|
this.hooks = hooks ?? {};
|
|
1020
2074
|
}
|
|
1021
2075
|
/**
|
|
@@ -1071,12 +2125,12 @@ var EventBus = class {
|
|
|
1071
2125
|
};
|
|
1072
2126
|
|
|
1073
2127
|
// src/health/jetstream.health-indicator.ts
|
|
1074
|
-
import { Injectable, Logger as
|
|
2128
|
+
import { Injectable, Logger as Logger7 } from "@nestjs/common";
|
|
1075
2129
|
var JetstreamHealthIndicator = class {
|
|
1076
2130
|
constructor(connection) {
|
|
1077
2131
|
this.connection = connection;
|
|
1078
2132
|
}
|
|
1079
|
-
logger = new
|
|
2133
|
+
logger = new Logger7("Jetstream:Health");
|
|
1080
2134
|
/**
|
|
1081
2135
|
* Plain health status check.
|
|
1082
2136
|
*
|
|
@@ -1282,7 +2336,7 @@ var JetstreamStrategy = class extends Server {
|
|
|
1282
2336
|
};
|
|
1283
2337
|
|
|
1284
2338
|
// src/server/core-rpc.server.ts
|
|
1285
|
-
import { Logger as
|
|
2339
|
+
import { Logger as Logger8 } from "@nestjs/common";
|
|
1286
2340
|
import { headers as natsHeaders2 } from "@nats-io/transport-node";
|
|
1287
2341
|
|
|
1288
2342
|
// src/context/rpc.context.ts
|
|
@@ -1292,9 +2346,6 @@ var RpcContext = class extends BaseRpcContext {
|
|
|
1292
2346
|
_retryDelay;
|
|
1293
2347
|
_shouldTerminate = false;
|
|
1294
2348
|
_terminateReason;
|
|
1295
|
-
// ---------------------------------------------------------------------------
|
|
1296
|
-
// Message accessors
|
|
1297
|
-
// ---------------------------------------------------------------------------
|
|
1298
2349
|
/**
|
|
1299
2350
|
* Get the underlying NATS message.
|
|
1300
2351
|
*
|
|
@@ -1329,9 +2380,6 @@ var RpcContext = class extends BaseRpcContext {
|
|
|
1329
2380
|
isJetStream() {
|
|
1330
2381
|
return "ack" in this.args[0];
|
|
1331
2382
|
}
|
|
1332
|
-
// ---------------------------------------------------------------------------
|
|
1333
|
-
// JetStream metadata (return undefined for Core NATS messages)
|
|
1334
|
-
// ---------------------------------------------------------------------------
|
|
1335
2383
|
/** How many times this message has been delivered. */
|
|
1336
2384
|
getDeliveryCount() {
|
|
1337
2385
|
return this.asJetStream()?.info.deliveryCount;
|
|
@@ -1353,9 +2401,6 @@ var RpcContext = class extends BaseRpcContext {
|
|
|
1353
2401
|
getCallerName() {
|
|
1354
2402
|
return this.getHeader("x-caller-name" /* CallerName */);
|
|
1355
2403
|
}
|
|
1356
|
-
// ---------------------------------------------------------------------------
|
|
1357
|
-
// Handler-controlled settlement
|
|
1358
|
-
// ---------------------------------------------------------------------------
|
|
1359
2404
|
/**
|
|
1360
2405
|
* Signal the transport to retry (nak) this message instead of acknowledging it.
|
|
1361
2406
|
*
|
|
@@ -1400,9 +2445,6 @@ var RpcContext = class extends BaseRpcContext {
|
|
|
1400
2445
|
throw new Error(`${method}() is only available for JetStream messages`);
|
|
1401
2446
|
}
|
|
1402
2447
|
}
|
|
1403
|
-
// ---------------------------------------------------------------------------
|
|
1404
|
-
// Transport-facing state (read by EventRouter)
|
|
1405
|
-
// ---------------------------------------------------------------------------
|
|
1406
2448
|
/** @internal */
|
|
1407
2449
|
get shouldRetry() {
|
|
1408
2450
|
return this._shouldRetry;
|
|
@@ -1524,7 +2566,7 @@ var unwrapResult = (result) => {
|
|
|
1524
2566
|
}
|
|
1525
2567
|
return result;
|
|
1526
2568
|
};
|
|
1527
|
-
var
|
|
2569
|
+
var isPromiseLike2 = (value) => value !== null && typeof value === "object" && typeof value.then === "function";
|
|
1528
2570
|
var subscribeToFirst = (obs) => new Promise((resolve, reject) => {
|
|
1529
2571
|
let done = false;
|
|
1530
2572
|
let subscription = null;
|
|
@@ -1554,20 +2596,25 @@ var subscribeToFirst = (obs) => new Promise((resolve, reject) => {
|
|
|
1554
2596
|
// src/server/core-rpc.server.ts
|
|
1555
2597
|
var CoreRpcServer = class {
|
|
1556
2598
|
constructor(options, connection, patternRegistry, codec, eventBus) {
|
|
1557
|
-
this.options = options;
|
|
1558
2599
|
this.connection = connection;
|
|
1559
2600
|
this.patternRegistry = patternRegistry;
|
|
1560
2601
|
this.codec = codec;
|
|
1561
2602
|
this.eventBus = eventBus;
|
|
2603
|
+
const derived = deriveOtelAttrs(options);
|
|
2604
|
+
this.otel = derived.otel;
|
|
2605
|
+
this.serviceName = derived.serviceName;
|
|
2606
|
+
this.serverEndpoint = derived.serverEndpoint;
|
|
1562
2607
|
}
|
|
1563
|
-
logger = new
|
|
2608
|
+
logger = new Logger8("Jetstream:CoreRpc");
|
|
1564
2609
|
subscription = null;
|
|
2610
|
+
otel;
|
|
2611
|
+
serviceName;
|
|
2612
|
+
serverEndpoint;
|
|
1565
2613
|
/** Start listening for RPC requests on the command subject. */
|
|
1566
2614
|
async start() {
|
|
1567
2615
|
const nc = await this.connection.getConnection();
|
|
1568
|
-
const
|
|
1569
|
-
const
|
|
1570
|
-
const queue = `${serviceName}_cmd_queue`;
|
|
2616
|
+
const subject = `${this.serviceName}.cmd.>`;
|
|
2617
|
+
const queue = `${this.serviceName}_cmd_queue`;
|
|
1571
2618
|
this.subscription = nc.subscribe(subject, {
|
|
1572
2619
|
queue,
|
|
1573
2620
|
callback: (err, msg) => {
|
|
@@ -1612,11 +2659,29 @@ var CoreRpcServer = class {
|
|
|
1612
2659
|
}
|
|
1613
2660
|
const ctx = new RpcContext([msg]);
|
|
1614
2661
|
try {
|
|
1615
|
-
const raw =
|
|
1616
|
-
|
|
1617
|
-
|
|
2662
|
+
const raw = await withConsumeSpan(
|
|
2663
|
+
{
|
|
2664
|
+
subject: msg.subject,
|
|
2665
|
+
msg,
|
|
2666
|
+
kind: "rpc" /* Rpc */,
|
|
2667
|
+
payloadBytes: msg.data.length,
|
|
2668
|
+
handlerMetadata: { pattern: msg.subject },
|
|
2669
|
+
serviceName: this.serviceName,
|
|
2670
|
+
endpoint: this.serverEndpoint
|
|
2671
|
+
},
|
|
2672
|
+
this.otel,
|
|
2673
|
+
() => {
|
|
2674
|
+
const out = unwrapResult(handler(data, ctx));
|
|
2675
|
+
return isPromiseLike2(out) ? out : out;
|
|
2676
|
+
}
|
|
2677
|
+
);
|
|
2678
|
+
msg.respond(this.codec.encode(raw));
|
|
1618
2679
|
} catch (err) {
|
|
1619
|
-
this.
|
|
2680
|
+
this.eventBus.emit(
|
|
2681
|
+
"error" /* Error */,
|
|
2682
|
+
err instanceof Error ? err : new Error(String(err)),
|
|
2683
|
+
`core-rpc-handler:${msg.subject}`
|
|
2684
|
+
);
|
|
1620
2685
|
this.respondWithError(msg, err);
|
|
1621
2686
|
}
|
|
1622
2687
|
}
|
|
@@ -1633,7 +2698,7 @@ var CoreRpcServer = class {
|
|
|
1633
2698
|
};
|
|
1634
2699
|
|
|
1635
2700
|
// src/server/infrastructure/stream.provider.ts
|
|
1636
|
-
import { Logger as
|
|
2701
|
+
import { Logger as Logger10 } from "@nestjs/common";
|
|
1637
2702
|
import { JetStreamApiError as JetStreamApiError2 } from "@nats-io/jetstream";
|
|
1638
2703
|
|
|
1639
2704
|
// src/server/infrastructure/nats-error-codes.ts
|
|
@@ -1700,7 +2765,7 @@ var isEqual = (a, b) => {
|
|
|
1700
2765
|
};
|
|
1701
2766
|
|
|
1702
2767
|
// src/server/infrastructure/stream-migration.ts
|
|
1703
|
-
import { Logger as
|
|
2768
|
+
import { Logger as Logger9 } from "@nestjs/common";
|
|
1704
2769
|
import { JetStreamApiError } from "@nats-io/jetstream";
|
|
1705
2770
|
var MIGRATION_BACKUP_SUFFIX = "__migration_backup";
|
|
1706
2771
|
var DEFAULT_SOURCING_TIMEOUT_MS = 3e4;
|
|
@@ -1709,7 +2774,7 @@ var StreamMigration = class {
|
|
|
1709
2774
|
constructor(sourcingTimeoutMs = DEFAULT_SOURCING_TIMEOUT_MS) {
|
|
1710
2775
|
this.sourcingTimeoutMs = sourcingTimeoutMs;
|
|
1711
2776
|
}
|
|
1712
|
-
logger = new
|
|
2777
|
+
logger = new Logger9("Jetstream:Stream");
|
|
1713
2778
|
async migrate(jsm, streamName2, newConfig) {
|
|
1714
2779
|
const backupName = `${streamName2}${MIGRATION_BACKUP_SUFFIX}`;
|
|
1715
2780
|
const startTime = Date.now();
|
|
@@ -1791,9 +2856,16 @@ var StreamProvider = class {
|
|
|
1791
2856
|
constructor(options, connection) {
|
|
1792
2857
|
this.options = options;
|
|
1793
2858
|
this.connection = connection;
|
|
2859
|
+
const derived = deriveOtelAttrs(options);
|
|
2860
|
+
this.otel = derived.otel;
|
|
2861
|
+
this.otelServiceName = derived.serviceName;
|
|
2862
|
+
this.otelEndpoint = derived.serverEndpoint;
|
|
1794
2863
|
}
|
|
1795
|
-
logger = new
|
|
2864
|
+
logger = new Logger10("Jetstream:Stream");
|
|
1796
2865
|
migration = new StreamMigration();
|
|
2866
|
+
otel;
|
|
2867
|
+
otelServiceName;
|
|
2868
|
+
otelEndpoint;
|
|
1797
2869
|
/**
|
|
1798
2870
|
* Ensure all required streams exist with correct configuration.
|
|
1799
2871
|
*
|
|
@@ -1839,32 +2911,56 @@ var StreamProvider = class {
|
|
|
1839
2911
|
/** Ensure a single stream exists, creating or updating as needed. */
|
|
1840
2912
|
async ensureStream(jsm, kind) {
|
|
1841
2913
|
const config = this.buildConfig(kind);
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
2914
|
+
return withProvisioningSpan(
|
|
2915
|
+
this.otel,
|
|
2916
|
+
{
|
|
2917
|
+
serviceName: this.otelServiceName,
|
|
2918
|
+
endpoint: this.otelEndpoint,
|
|
2919
|
+
entity: "stream",
|
|
2920
|
+
name: config.name,
|
|
2921
|
+
action: "ensure"
|
|
2922
|
+
},
|
|
2923
|
+
async () => {
|
|
2924
|
+
this.logger.log(`Ensuring stream: ${config.name}`);
|
|
2925
|
+
try {
|
|
2926
|
+
const currentInfo = await jsm.streams.info(config.name);
|
|
2927
|
+
return await this.handleExistingStream(jsm, currentInfo, config);
|
|
2928
|
+
} catch (err) {
|
|
2929
|
+
if (err instanceof JetStreamApiError2 && err.apiError().err_code === 10059 /* StreamNotFound */) {
|
|
2930
|
+
this.logger.log(`Creating stream: ${config.name}`);
|
|
2931
|
+
return await jsm.streams.add(config);
|
|
2932
|
+
}
|
|
2933
|
+
throw err;
|
|
2934
|
+
}
|
|
1850
2935
|
}
|
|
1851
|
-
|
|
1852
|
-
}
|
|
2936
|
+
);
|
|
1853
2937
|
}
|
|
1854
2938
|
/** Ensure a dead-letter queue stream exists, creating or updating as needed. */
|
|
1855
2939
|
async ensureDlqStream(jsm) {
|
|
1856
2940
|
const config = this.buildDlqConfig();
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
2941
|
+
return withProvisioningSpan(
|
|
2942
|
+
this.otel,
|
|
2943
|
+
{
|
|
2944
|
+
serviceName: this.otelServiceName,
|
|
2945
|
+
endpoint: this.otelEndpoint,
|
|
2946
|
+
entity: "stream",
|
|
2947
|
+
name: config.name,
|
|
2948
|
+
action: "ensure"
|
|
2949
|
+
},
|
|
2950
|
+
async () => {
|
|
2951
|
+
this.logger.log(`Ensuring DLQ stream: ${config.name}`);
|
|
2952
|
+
try {
|
|
2953
|
+
const currentInfo = await jsm.streams.info(config.name);
|
|
2954
|
+
return await this.handleExistingStream(jsm, currentInfo, config);
|
|
2955
|
+
} catch (err) {
|
|
2956
|
+
if (err instanceof JetStreamApiError2 && err.apiError().err_code === 10059 /* StreamNotFound */) {
|
|
2957
|
+
this.logger.log(`Creating DLQ stream: ${config.name}`);
|
|
2958
|
+
return await jsm.streams.add(config);
|
|
2959
|
+
}
|
|
2960
|
+
throw err;
|
|
2961
|
+
}
|
|
1865
2962
|
}
|
|
1866
|
-
|
|
1867
|
-
}
|
|
2963
|
+
);
|
|
1868
2964
|
}
|
|
1869
2965
|
async handleExistingStream(jsm, currentInfo, config) {
|
|
1870
2966
|
const diff = compareStreamConfig(currentInfo.config, config);
|
|
@@ -1893,7 +2989,18 @@ var StreamProvider = class {
|
|
|
1893
2989
|
}
|
|
1894
2990
|
return currentInfo;
|
|
1895
2991
|
}
|
|
1896
|
-
await
|
|
2992
|
+
await withMigrationSpan(
|
|
2993
|
+
this.otel,
|
|
2994
|
+
{
|
|
2995
|
+
serviceName: this.otelServiceName,
|
|
2996
|
+
endpoint: this.otelEndpoint,
|
|
2997
|
+
stream: config.name,
|
|
2998
|
+
reason: diff.changes.filter((c) => c.mutability === "immutable").map((c) => c.property).join(", ")
|
|
2999
|
+
},
|
|
3000
|
+
async () => {
|
|
3001
|
+
await this.migration.migrate(jsm, config.name, config);
|
|
3002
|
+
}
|
|
3003
|
+
);
|
|
1897
3004
|
return await jsm.streams.info(config.name);
|
|
1898
3005
|
}
|
|
1899
3006
|
buildMutableOnlyConfig(config, currentConfig, diff) {
|
|
@@ -2009,7 +3116,7 @@ var StreamProvider = class {
|
|
|
2009
3116
|
};
|
|
2010
3117
|
|
|
2011
3118
|
// src/server/infrastructure/consumer.provider.ts
|
|
2012
|
-
import { Logger as
|
|
3119
|
+
import { Logger as Logger11 } from "@nestjs/common";
|
|
2013
3120
|
import { JetStreamApiError as JetStreamApiError3 } from "@nats-io/jetstream";
|
|
2014
3121
|
var ConsumerProvider = class {
|
|
2015
3122
|
constructor(options, connection, streamProvider, patternRegistry) {
|
|
@@ -2017,8 +3124,15 @@ var ConsumerProvider = class {
|
|
|
2017
3124
|
this.connection = connection;
|
|
2018
3125
|
this.streamProvider = streamProvider;
|
|
2019
3126
|
this.patternRegistry = patternRegistry;
|
|
2020
|
-
|
|
2021
|
-
|
|
3127
|
+
const derived = deriveOtelAttrs(options);
|
|
3128
|
+
this.otel = derived.otel;
|
|
3129
|
+
this.otelServiceName = derived.serviceName;
|
|
3130
|
+
this.otelEndpoint = derived.serverEndpoint;
|
|
3131
|
+
}
|
|
3132
|
+
logger = new Logger11("Jetstream:Consumer");
|
|
3133
|
+
otel;
|
|
3134
|
+
otelServiceName;
|
|
3135
|
+
otelEndpoint;
|
|
2022
3136
|
/**
|
|
2023
3137
|
* Ensure consumers exist for the specified kinds.
|
|
2024
3138
|
*
|
|
@@ -2048,17 +3162,29 @@ var ConsumerProvider = class {
|
|
|
2048
3162
|
const stream = this.streamProvider.getStreamName(kind);
|
|
2049
3163
|
const config = this.buildConfig(kind);
|
|
2050
3164
|
const name = config.durable_name;
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
3165
|
+
return withProvisioningSpan(
|
|
3166
|
+
this.otel,
|
|
3167
|
+
{
|
|
3168
|
+
serviceName: this.otelServiceName,
|
|
3169
|
+
endpoint: this.otelEndpoint,
|
|
3170
|
+
entity: "consumer",
|
|
3171
|
+
name,
|
|
3172
|
+
action: "ensure"
|
|
3173
|
+
},
|
|
3174
|
+
async () => {
|
|
3175
|
+
this.logger.log(`Ensuring consumer: ${name} on stream: ${stream}`);
|
|
3176
|
+
try {
|
|
3177
|
+
await jsm.consumers.info(stream, name);
|
|
3178
|
+
this.logger.debug(`Consumer exists, updating: ${name}`);
|
|
3179
|
+
return await jsm.consumers.update(stream, name, config);
|
|
3180
|
+
} catch (err) {
|
|
3181
|
+
if (!(err instanceof JetStreamApiError3) || err.apiError().err_code !== 10014 /* ConsumerNotFound */) {
|
|
3182
|
+
throw err;
|
|
3183
|
+
}
|
|
3184
|
+
return await this.createConsumer(jsm, stream, name, config);
|
|
3185
|
+
}
|
|
2059
3186
|
}
|
|
2060
|
-
|
|
2061
|
-
}
|
|
3187
|
+
);
|
|
2062
3188
|
}
|
|
2063
3189
|
/**
|
|
2064
3190
|
* Recover a consumer that disappeared during runtime.
|
|
@@ -2077,16 +3203,28 @@ var ConsumerProvider = class {
|
|
|
2077
3203
|
const stream = this.streamProvider.getStreamName(kind);
|
|
2078
3204
|
const config = this.buildConfig(kind);
|
|
2079
3205
|
const name = config.durable_name;
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
3206
|
+
return withProvisioningSpan(
|
|
3207
|
+
this.otel,
|
|
3208
|
+
{
|
|
3209
|
+
serviceName: this.otelServiceName,
|
|
3210
|
+
endpoint: this.otelEndpoint,
|
|
3211
|
+
entity: "consumer",
|
|
3212
|
+
name,
|
|
3213
|
+
action: "recover"
|
|
3214
|
+
},
|
|
3215
|
+
async () => {
|
|
3216
|
+
this.logger.log(`Recovering consumer: ${name} on stream: ${stream}`);
|
|
3217
|
+
await this.assertNoMigrationInProgress(jsm, stream);
|
|
3218
|
+
try {
|
|
3219
|
+
return await jsm.consumers.info(stream, name);
|
|
3220
|
+
} catch (err) {
|
|
3221
|
+
if (!(err instanceof JetStreamApiError3) || err.apiError().err_code !== 10014 /* ConsumerNotFound */) {
|
|
3222
|
+
throw err;
|
|
3223
|
+
}
|
|
3224
|
+
return await this.createConsumer(jsm, stream, name, config);
|
|
3225
|
+
}
|
|
2087
3226
|
}
|
|
2088
|
-
|
|
2089
|
-
}
|
|
3227
|
+
);
|
|
2090
3228
|
}
|
|
2091
3229
|
/**
|
|
2092
3230
|
* Throw if a migration backup stream exists for this stream.
|
|
@@ -2202,7 +3340,7 @@ var ConsumerProvider = class {
|
|
|
2202
3340
|
};
|
|
2203
3341
|
|
|
2204
3342
|
// src/server/infrastructure/message.provider.ts
|
|
2205
|
-
import { Logger as
|
|
3343
|
+
import { Logger as Logger12 } from "@nestjs/common";
|
|
2206
3344
|
import { DeliverPolicy as DeliverPolicy2 } from "@nats-io/jetstream";
|
|
2207
3345
|
import {
|
|
2208
3346
|
catchError,
|
|
@@ -2222,7 +3360,7 @@ var MessageProvider = class {
|
|
|
2222
3360
|
this.consumeOptionsMap = consumeOptionsMap;
|
|
2223
3361
|
this.consumerRecoveryFn = consumerRecoveryFn;
|
|
2224
3362
|
}
|
|
2225
|
-
logger = new
|
|
3363
|
+
logger = new Logger12("Jetstream:Message");
|
|
2226
3364
|
activeIterators = /* @__PURE__ */ new Set();
|
|
2227
3365
|
orderedReadyResolve = null;
|
|
2228
3366
|
orderedReadyReject = null;
|
|
@@ -2469,7 +3607,7 @@ var MessageProvider = class {
|
|
|
2469
3607
|
};
|
|
2470
3608
|
|
|
2471
3609
|
// src/server/infrastructure/metadata.provider.ts
|
|
2472
|
-
import { Logger as
|
|
3610
|
+
import { Logger as Logger13 } from "@nestjs/common";
|
|
2473
3611
|
import { Kvm } from "@nats-io/kv";
|
|
2474
3612
|
var MetadataProvider = class {
|
|
2475
3613
|
constructor(options, connection) {
|
|
@@ -2478,7 +3616,7 @@ var MetadataProvider = class {
|
|
|
2478
3616
|
this.replicas = options.metadata?.replicas ?? DEFAULT_METADATA_REPLICAS;
|
|
2479
3617
|
this.ttl = Math.max(options.metadata?.ttl ?? DEFAULT_METADATA_TTL, MIN_METADATA_TTL);
|
|
2480
3618
|
}
|
|
2481
|
-
logger = new
|
|
3619
|
+
logger = new Logger13("Jetstream:Metadata");
|
|
2482
3620
|
bucketName;
|
|
2483
3621
|
replicas;
|
|
2484
3622
|
ttl;
|
|
@@ -2571,7 +3709,7 @@ var MetadataProvider = class {
|
|
|
2571
3709
|
};
|
|
2572
3710
|
|
|
2573
3711
|
// src/server/routing/pattern-registry.ts
|
|
2574
|
-
import { Logger as
|
|
3712
|
+
import { Logger as Logger14 } from "@nestjs/common";
|
|
2575
3713
|
var HANDLER_LABELS = {
|
|
2576
3714
|
["broadcast" /* Broadcast */]: "broadcast" /* Broadcast */,
|
|
2577
3715
|
["ordered" /* Ordered */]: "ordered" /* Ordered */,
|
|
@@ -2582,7 +3720,7 @@ var PatternRegistry = class {
|
|
|
2582
3720
|
constructor(options) {
|
|
2583
3721
|
this.options = options;
|
|
2584
3722
|
}
|
|
2585
|
-
logger = new
|
|
3723
|
+
logger = new Logger14("Jetstream:PatternRegistry");
|
|
2586
3724
|
registry = /* @__PURE__ */ new Map();
|
|
2587
3725
|
// Cached after registerHandlers() — the registry is immutable from that point
|
|
2588
3726
|
cachedPatterns = null;
|
|
@@ -2739,8 +3877,13 @@ var PatternRegistry = class {
|
|
|
2739
3877
|
};
|
|
2740
3878
|
|
|
2741
3879
|
// src/server/routing/event.router.ts
|
|
2742
|
-
import { Logger as
|
|
3880
|
+
import { Logger as Logger15 } from "@nestjs/common";
|
|
2743
3881
|
import { headers as natsHeaders3 } from "@nats-io/transport-node";
|
|
3882
|
+
var eventConsumeKindFor = (kind) => {
|
|
3883
|
+
if (kind === "broadcast" /* Broadcast */) return "broadcast" /* Broadcast */;
|
|
3884
|
+
if (kind === "ordered" /* Ordered */) return "ordered" /* Ordered */;
|
|
3885
|
+
return "event" /* Event */;
|
|
3886
|
+
};
|
|
2744
3887
|
var EventRouter = class {
|
|
2745
3888
|
constructor(messageProvider, patternRegistry, codec, eventBus, deadLetterConfig, processingConfig, ackWaitMap, connection, options) {
|
|
2746
3889
|
this.messageProvider = messageProvider;
|
|
@@ -2752,9 +3895,22 @@ var EventRouter = class {
|
|
|
2752
3895
|
this.ackWaitMap = ackWaitMap;
|
|
2753
3896
|
this.connection = connection;
|
|
2754
3897
|
this.options = options;
|
|
3898
|
+
if (options) {
|
|
3899
|
+
const derived = deriveOtelAttrs(options);
|
|
3900
|
+
this.otel = derived.otel;
|
|
3901
|
+
this.serviceName = derived.serviceName;
|
|
3902
|
+
this.serverEndpoint = derived.serverEndpoint;
|
|
3903
|
+
} else {
|
|
3904
|
+
this.otel = resolveOtelOptions({ enabled: false });
|
|
3905
|
+
this.serviceName = "";
|
|
3906
|
+
this.serverEndpoint = null;
|
|
3907
|
+
}
|
|
2755
3908
|
}
|
|
2756
|
-
logger = new
|
|
3909
|
+
logger = new Logger15("Jetstream:EventRouter");
|
|
2757
3910
|
subscriptions = [];
|
|
3911
|
+
otel;
|
|
3912
|
+
serviceName;
|
|
3913
|
+
serverEndpoint;
|
|
2758
3914
|
/**
|
|
2759
3915
|
* Update the max_deliver thresholds from actual NATS consumer configs.
|
|
2760
3916
|
* Called after consumers are ensured so the DLQ map reflects reality.
|
|
@@ -2784,8 +3940,12 @@ var EventRouter = class {
|
|
|
2784
3940
|
const patternRegistry = this.patternRegistry;
|
|
2785
3941
|
const codec = this.codec;
|
|
2786
3942
|
const eventBus = this.eventBus;
|
|
2787
|
-
const
|
|
3943
|
+
const logger5 = this.logger;
|
|
2788
3944
|
const deadLetterConfig = this.deadLetterConfig;
|
|
3945
|
+
const otel = this.otel;
|
|
3946
|
+
const serviceName = this.serviceName;
|
|
3947
|
+
const serverEndpoint = this.serverEndpoint;
|
|
3948
|
+
const spanKind = eventConsumeKindFor(kind);
|
|
2789
3949
|
const ackExtensionInterval = isOrdered ? null : resolveAckExtensionInterval(this.getAckExtensionConfig(kind), this.ackWaitMap?.get(kind));
|
|
2790
3950
|
const hasAckExtension = ackExtensionInterval !== null && ackExtensionInterval > 0;
|
|
2791
3951
|
const concurrency = this.getConcurrency(kind);
|
|
@@ -2816,7 +3976,7 @@ var EventRouter = class {
|
|
|
2816
3976
|
const handler = patternRegistry.getHandler(subject);
|
|
2817
3977
|
if (!handler) {
|
|
2818
3978
|
msg.term(`No handler for event: ${subject}`);
|
|
2819
|
-
|
|
3979
|
+
logger5.error(`No handler for subject: ${subject}`);
|
|
2820
3980
|
return null;
|
|
2821
3981
|
}
|
|
2822
3982
|
let data;
|
|
@@ -2824,17 +3984,17 @@ var EventRouter = class {
|
|
|
2824
3984
|
data = codec.decode(msg.data);
|
|
2825
3985
|
} catch (err) {
|
|
2826
3986
|
msg.term("Decode error");
|
|
2827
|
-
|
|
3987
|
+
logger5.error(`Decode error for ${subject}:`, err);
|
|
2828
3988
|
return null;
|
|
2829
3989
|
}
|
|
2830
3990
|
if (emitRouted) eventBus.emitMessageRouted(subject, "event" /* Event */);
|
|
2831
3991
|
return { handler, data };
|
|
2832
3992
|
} catch (err) {
|
|
2833
|
-
|
|
3993
|
+
logger5.error(`Unexpected error in ${kind} event router`, err);
|
|
2834
3994
|
try {
|
|
2835
3995
|
msg.term("Unexpected router error");
|
|
2836
3996
|
} catch (termErr) {
|
|
2837
|
-
|
|
3997
|
+
logger5.error(`Failed to terminate message ${subject}:`, termErr);
|
|
2838
3998
|
}
|
|
2839
3999
|
return null;
|
|
2840
4000
|
}
|
|
@@ -2847,13 +4007,31 @@ var EventRouter = class {
|
|
|
2847
4007
|
const stopAckExtension = hasAckExtension ? startAckExtensionTimer(msg, ackExtensionInterval) : null;
|
|
2848
4008
|
let pending;
|
|
2849
4009
|
try {
|
|
2850
|
-
pending =
|
|
4010
|
+
pending = withConsumeSpan(
|
|
4011
|
+
{
|
|
4012
|
+
subject: msg.subject,
|
|
4013
|
+
msg,
|
|
4014
|
+
info: msg.info,
|
|
4015
|
+
kind: spanKind,
|
|
4016
|
+
payloadBytes: msg.data.length,
|
|
4017
|
+
handlerMetadata: { pattern: msg.subject },
|
|
4018
|
+
serviceName,
|
|
4019
|
+
endpoint: serverEndpoint
|
|
4020
|
+
},
|
|
4021
|
+
otel,
|
|
4022
|
+
() => unwrapResult(handler(data, ctx))
|
|
4023
|
+
);
|
|
2851
4024
|
} catch (err) {
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
4025
|
+
eventBus.emit(
|
|
4026
|
+
"error" /* Error */,
|
|
4027
|
+
err instanceof Error ? err : new Error(String(err)),
|
|
4028
|
+
`${kind}-handler:${msg.subject}`
|
|
4029
|
+
);
|
|
4030
|
+
return settleFailure(msg, data, err).finally(() => {
|
|
4031
|
+
if (stopAckExtension !== null) stopAckExtension();
|
|
4032
|
+
});
|
|
2855
4033
|
}
|
|
2856
|
-
if (!
|
|
4034
|
+
if (!isPromiseLike2(pending)) {
|
|
2857
4035
|
settleSuccess(msg, ctx);
|
|
2858
4036
|
if (stopAckExtension !== null) stopAckExtension();
|
|
2859
4037
|
return void 0;
|
|
@@ -2864,7 +4042,11 @@ var EventRouter = class {
|
|
|
2864
4042
|
if (stopAckExtension !== null) stopAckExtension();
|
|
2865
4043
|
},
|
|
2866
4044
|
async (err) => {
|
|
2867
|
-
|
|
4045
|
+
eventBus.emit(
|
|
4046
|
+
"error" /* Error */,
|
|
4047
|
+
err instanceof Error ? err : new Error(String(err)),
|
|
4048
|
+
`${kind}-handler:${msg.subject}`
|
|
4049
|
+
);
|
|
2868
4050
|
try {
|
|
2869
4051
|
await settleFailure(msg, data, err);
|
|
2870
4052
|
} finally {
|
|
@@ -2880,41 +4062,54 @@ var EventRouter = class {
|
|
|
2880
4062
|
try {
|
|
2881
4063
|
handler = patternRegistry.getHandler(subject);
|
|
2882
4064
|
if (!handler) {
|
|
2883
|
-
|
|
4065
|
+
logger5.error(`No handler for subject: ${subject}`);
|
|
2884
4066
|
return void 0;
|
|
2885
4067
|
}
|
|
2886
4068
|
try {
|
|
2887
4069
|
data = codec.decode(msg.data);
|
|
2888
4070
|
} catch (err) {
|
|
2889
|
-
|
|
4071
|
+
logger5.error(`Decode error for ${subject}:`, err);
|
|
2890
4072
|
return void 0;
|
|
2891
4073
|
}
|
|
2892
4074
|
if (emitRouted) eventBus.emitMessageRouted(subject, "event" /* Event */);
|
|
2893
4075
|
} catch (err) {
|
|
2894
|
-
|
|
4076
|
+
logger5.error(`Ordered handler error (${subject}):`, err);
|
|
2895
4077
|
return void 0;
|
|
2896
4078
|
}
|
|
2897
4079
|
const ctx = new RpcContext([msg]);
|
|
2898
4080
|
const warnIfSettlementAttempted = () => {
|
|
2899
4081
|
if (ctx.shouldRetry || ctx.shouldTerminate) {
|
|
2900
|
-
|
|
4082
|
+
logger5.warn(
|
|
2901
4083
|
`retry()/terminate() ignored for ordered message ${subject} \u2014 ordered consumers auto-acknowledge`
|
|
2902
4084
|
);
|
|
2903
4085
|
}
|
|
2904
4086
|
};
|
|
2905
4087
|
let pending;
|
|
2906
4088
|
try {
|
|
2907
|
-
pending =
|
|
4089
|
+
pending = withConsumeSpan(
|
|
4090
|
+
{
|
|
4091
|
+
subject: msg.subject,
|
|
4092
|
+
msg,
|
|
4093
|
+
info: msg.info,
|
|
4094
|
+
kind: spanKind,
|
|
4095
|
+
payloadBytes: msg.data.length,
|
|
4096
|
+
handlerMetadata: { pattern: msg.subject },
|
|
4097
|
+
serviceName,
|
|
4098
|
+
endpoint: serverEndpoint
|
|
4099
|
+
},
|
|
4100
|
+
otel,
|
|
4101
|
+
() => unwrapResult(handler(data, ctx))
|
|
4102
|
+
);
|
|
2908
4103
|
} catch (err) {
|
|
2909
|
-
|
|
4104
|
+
logger5.error(`Ordered handler error (${subject}):`, err);
|
|
2910
4105
|
return void 0;
|
|
2911
4106
|
}
|
|
2912
|
-
if (!
|
|
4107
|
+
if (!isPromiseLike2(pending)) {
|
|
2913
4108
|
warnIfSettlementAttempted();
|
|
2914
4109
|
return void 0;
|
|
2915
4110
|
}
|
|
2916
4111
|
return pending.then(warnIfSettlementAttempted, (err) => {
|
|
2917
|
-
|
|
4112
|
+
logger5.error(`Ordered handler error (${subject}):`, err);
|
|
2918
4113
|
});
|
|
2919
4114
|
};
|
|
2920
4115
|
const route = isOrdered ? handleOrderedSafe : handleSafe;
|
|
@@ -2947,7 +4142,7 @@ var EventRouter = class {
|
|
|
2947
4142
|
backlog.push(msg);
|
|
2948
4143
|
if (!backlogWarned && backlog.length >= backlogWarnThreshold) {
|
|
2949
4144
|
backlogWarned = true;
|
|
2950
|
-
|
|
4145
|
+
logger5.warn(
|
|
2951
4146
|
`${kind} backlog reached ${backlog.length} messages \u2014 consumer may be falling behind`
|
|
2952
4147
|
);
|
|
2953
4148
|
}
|
|
@@ -2963,7 +4158,7 @@ var EventRouter = class {
|
|
|
2963
4158
|
}
|
|
2964
4159
|
},
|
|
2965
4160
|
error: (err) => {
|
|
2966
|
-
|
|
4161
|
+
logger5.error(`Stream error in ${kind} router`, err);
|
|
2967
4162
|
}
|
|
2968
4163
|
});
|
|
2969
4164
|
this.subscriptions.push(subscription);
|
|
@@ -2978,14 +4173,11 @@ var EventRouter = class {
|
|
|
2978
4173
|
if (kind === "broadcast" /* Broadcast */) return this.processingConfig?.broadcast?.ackExtension;
|
|
2979
4174
|
return void 0;
|
|
2980
4175
|
}
|
|
2981
|
-
/** Handle a dead letter: invoke callback, then term or nak based on result. */
|
|
2982
4176
|
/**
|
|
2983
|
-
*
|
|
2984
|
-
*
|
|
2985
|
-
*
|
|
2986
|
-
*
|
|
2987
|
-
* On success, terminates the message. On error, leaves it unacknowledged (nak)
|
|
2988
|
-
* so NATS can retry the delivery on the next cycle.
|
|
4177
|
+
* Last-resort path for a dead letter: invoke `onDeadLetter`, then `term` on
|
|
4178
|
+
* success or `nak` on hook failure so NATS retries on the next delivery
|
|
4179
|
+
* cycle. Used when DLQ stream isn't configured, or when publishing to it
|
|
4180
|
+
* failed and we still have to surface the message somewhere observable.
|
|
2989
4181
|
*/
|
|
2990
4182
|
async fallbackToOnDeadLetterCallback(info, msg) {
|
|
2991
4183
|
if (!this.deadLetterConfig) {
|
|
@@ -3077,20 +4269,37 @@ var EventRouter = class {
|
|
|
3077
4269
|
streamSequence: msg.info.streamSequence,
|
|
3078
4270
|
timestamp: new Date(msg.info.timestampNanos / 1e6).toISOString()
|
|
3079
4271
|
};
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
4272
|
+
await withDeadLetterSpan(
|
|
4273
|
+
{
|
|
4274
|
+
msg,
|
|
4275
|
+
// Pattern resolution mirrors event-routing: when a registered
|
|
4276
|
+
// pattern matches, surface it on the DLQ span so APM can filter
|
|
4277
|
+
// dead letters by handler without parsing the subject. Falls back
|
|
4278
|
+
// to the subject itself when no glob handler is in play.
|
|
4279
|
+
pattern: this.patternRegistry.getHandler(msg.subject) ? msg.subject : void 0,
|
|
4280
|
+
finalDeliveryCount: msg.info.deliveryCount,
|
|
4281
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
4282
|
+
serviceName: this.serviceName,
|
|
4283
|
+
endpoint: this.serverEndpoint
|
|
4284
|
+
},
|
|
4285
|
+
this.otel,
|
|
4286
|
+
async () => {
|
|
4287
|
+
this.eventBus.emit("deadLetter" /* DeadLetter */, info);
|
|
4288
|
+
if (!this.options?.dlq) {
|
|
4289
|
+
await this.fallbackToOnDeadLetterCallback(info, msg);
|
|
4290
|
+
} else {
|
|
4291
|
+
await this.publishToDlq(msg, info, error);
|
|
4292
|
+
}
|
|
4293
|
+
}
|
|
4294
|
+
);
|
|
3086
4295
|
}
|
|
3087
4296
|
};
|
|
3088
4297
|
|
|
3089
4298
|
// src/server/routing/rpc.router.ts
|
|
3090
|
-
import { Logger as
|
|
4299
|
+
import { Logger as Logger16 } from "@nestjs/common";
|
|
3091
4300
|
import { headers } from "@nats-io/transport-node";
|
|
3092
4301
|
var RpcRouter = class {
|
|
3093
|
-
constructor(messageProvider, patternRegistry, connection, codec, eventBus, rpcOptions, ackWaitMap) {
|
|
4302
|
+
constructor(messageProvider, patternRegistry, connection, codec, eventBus, rpcOptions, ackWaitMap, options) {
|
|
3094
4303
|
this.messageProvider = messageProvider;
|
|
3095
4304
|
this.patternRegistry = patternRegistry;
|
|
3096
4305
|
this.connection = connection;
|
|
@@ -3100,13 +4309,26 @@ var RpcRouter = class {
|
|
|
3100
4309
|
this.ackWaitMap = ackWaitMap;
|
|
3101
4310
|
this.timeout = rpcOptions?.timeout ?? DEFAULT_JETSTREAM_RPC_TIMEOUT;
|
|
3102
4311
|
this.concurrency = rpcOptions?.concurrency;
|
|
4312
|
+
if (options) {
|
|
4313
|
+
const derived = deriveOtelAttrs(options);
|
|
4314
|
+
this.otel = derived.otel;
|
|
4315
|
+
this.serviceName = derived.serviceName;
|
|
4316
|
+
this.serverEndpoint = derived.serverEndpoint;
|
|
4317
|
+
} else {
|
|
4318
|
+
this.otel = resolveOtelOptions({ enabled: false });
|
|
4319
|
+
this.serviceName = "";
|
|
4320
|
+
this.serverEndpoint = null;
|
|
4321
|
+
}
|
|
3103
4322
|
}
|
|
3104
|
-
logger = new
|
|
4323
|
+
logger = new Logger16("Jetstream:RpcRouter");
|
|
3105
4324
|
timeout;
|
|
3106
4325
|
concurrency;
|
|
3107
4326
|
resolvedAckExtensionInterval;
|
|
3108
4327
|
subscription = null;
|
|
3109
4328
|
cachedNc = null;
|
|
4329
|
+
otel;
|
|
4330
|
+
serviceName;
|
|
4331
|
+
serverEndpoint;
|
|
3110
4332
|
/** Lazily resolve the ack extension interval (needs ackWaitMap populated at runtime). */
|
|
3111
4333
|
get ackExtensionInterval() {
|
|
3112
4334
|
if (this.resolvedAckExtensionInterval !== void 0) return this.resolvedAckExtensionInterval;
|
|
@@ -3123,11 +4345,14 @@ var RpcRouter = class {
|
|
|
3123
4345
|
const patternRegistry = this.patternRegistry;
|
|
3124
4346
|
const codec = this.codec;
|
|
3125
4347
|
const eventBus = this.eventBus;
|
|
3126
|
-
const
|
|
4348
|
+
const logger5 = this.logger;
|
|
3127
4349
|
const timeout = this.timeout;
|
|
3128
4350
|
const ackExtensionInterval = this.ackExtensionInterval;
|
|
3129
4351
|
const hasAckExtension = ackExtensionInterval !== null && ackExtensionInterval > 0;
|
|
3130
4352
|
const maxActive = this.concurrency ?? Number.POSITIVE_INFINITY;
|
|
4353
|
+
const otel = this.otel;
|
|
4354
|
+
const serviceName = this.serviceName;
|
|
4355
|
+
const serverEndpoint = this.serverEndpoint;
|
|
3131
4356
|
const emitRpcTimeout = (subject, correlationId) => {
|
|
3132
4357
|
eventBus.emit("rpcTimeout" /* RpcTimeout */, subject, correlationId);
|
|
3133
4358
|
};
|
|
@@ -3137,7 +4362,7 @@ var RpcRouter = class {
|
|
|
3137
4362
|
hdrs.set("x-correlation-id" /* CorrelationId */, correlationId);
|
|
3138
4363
|
nc.publish(replyTo, codec.encode(payload), { headers: hdrs });
|
|
3139
4364
|
} catch (publishErr) {
|
|
3140
|
-
|
|
4365
|
+
logger5.error(`Failed to publish RPC response`, publishErr);
|
|
3141
4366
|
}
|
|
3142
4367
|
};
|
|
3143
4368
|
const publishErrorReply = (replyTo, correlationId, subject, err) => {
|
|
@@ -3147,7 +4372,7 @@ var RpcRouter = class {
|
|
|
3147
4372
|
hdrs.set("x-error" /* Error */, "true");
|
|
3148
4373
|
nc.publish(replyTo, codec.encode(serializeError(err)), { headers: hdrs });
|
|
3149
4374
|
} catch (encodeErr) {
|
|
3150
|
-
|
|
4375
|
+
logger5.error(`Failed to encode RPC error for ${subject}`, encodeErr);
|
|
3151
4376
|
}
|
|
3152
4377
|
};
|
|
3153
4378
|
const resolveCommand = (msg) => {
|
|
@@ -3156,7 +4381,7 @@ var RpcRouter = class {
|
|
|
3156
4381
|
const handler = patternRegistry.getHandler(subject);
|
|
3157
4382
|
if (!handler) {
|
|
3158
4383
|
msg.term(`No handler for RPC: ${subject}`);
|
|
3159
|
-
|
|
4384
|
+
logger5.error(`No handler for RPC subject: ${subject}`);
|
|
3160
4385
|
return null;
|
|
3161
4386
|
}
|
|
3162
4387
|
const msgHeaders = msg.headers;
|
|
@@ -3164,7 +4389,7 @@ var RpcRouter = class {
|
|
|
3164
4389
|
const correlationId = msgHeaders?.get("x-correlation-id" /* CorrelationId */);
|
|
3165
4390
|
if (!replyTo || !correlationId) {
|
|
3166
4391
|
msg.term("Missing required headers (reply-to or correlation-id)");
|
|
3167
|
-
|
|
4392
|
+
logger5.error(`Missing headers for RPC: ${subject}`);
|
|
3168
4393
|
return null;
|
|
3169
4394
|
}
|
|
3170
4395
|
let data;
|
|
@@ -3172,17 +4397,17 @@ var RpcRouter = class {
|
|
|
3172
4397
|
data = codec.decode(msg.data);
|
|
3173
4398
|
} catch (err) {
|
|
3174
4399
|
msg.term("Decode error");
|
|
3175
|
-
|
|
4400
|
+
logger5.error(`Decode error for RPC ${subject}:`, err);
|
|
3176
4401
|
return null;
|
|
3177
4402
|
}
|
|
3178
4403
|
eventBus.emitMessageRouted(subject, "rpc" /* Rpc */);
|
|
3179
4404
|
return { handler, data, replyTo, correlationId };
|
|
3180
4405
|
} catch (err) {
|
|
3181
|
-
|
|
4406
|
+
logger5.error("Unexpected error in RPC router", err);
|
|
3182
4407
|
try {
|
|
3183
4408
|
msg.term("Unexpected router error");
|
|
3184
4409
|
} catch (termErr) {
|
|
3185
|
-
|
|
4410
|
+
logger5.error(`Failed to terminate RPC message ${subject}:`, termErr);
|
|
3186
4411
|
}
|
|
3187
4412
|
return null;
|
|
3188
4413
|
}
|
|
@@ -3194,17 +4419,39 @@ var RpcRouter = class {
|
|
|
3194
4419
|
const subject = msg.subject;
|
|
3195
4420
|
const ctx = new RpcContext([msg]);
|
|
3196
4421
|
const stopAckExtension = hasAckExtension ? startAckExtensionTimer(msg, ackExtensionInterval) : null;
|
|
4422
|
+
const reportHandlerError = (err) => {
|
|
4423
|
+
eventBus.emit(
|
|
4424
|
+
"error" /* Error */,
|
|
4425
|
+
err instanceof Error ? err : new Error(String(err)),
|
|
4426
|
+
`rpc-handler:${subject}`
|
|
4427
|
+
);
|
|
4428
|
+
publishErrorReply(replyTo, correlationId, subject, err);
|
|
4429
|
+
msg.term(`Handler error: ${subject}`);
|
|
4430
|
+
};
|
|
4431
|
+
const abortController = new AbortController();
|
|
3197
4432
|
let pending;
|
|
3198
4433
|
try {
|
|
3199
|
-
pending =
|
|
4434
|
+
pending = withConsumeSpan(
|
|
4435
|
+
{
|
|
4436
|
+
subject,
|
|
4437
|
+
msg,
|
|
4438
|
+
info: msg.info,
|
|
4439
|
+
kind: "rpc" /* Rpc */,
|
|
4440
|
+
payloadBytes: msg.data.length,
|
|
4441
|
+
handlerMetadata: { pattern: subject },
|
|
4442
|
+
serviceName,
|
|
4443
|
+
endpoint: serverEndpoint
|
|
4444
|
+
},
|
|
4445
|
+
otel,
|
|
4446
|
+
() => unwrapResult(handler(data, ctx)),
|
|
4447
|
+
{ signal: abortController.signal, timeoutLabel: "rpc.handler.timeout" }
|
|
4448
|
+
);
|
|
3200
4449
|
} catch (err) {
|
|
3201
4450
|
if (stopAckExtension !== null) stopAckExtension();
|
|
3202
|
-
|
|
3203
|
-
publishErrorReply(replyTo, correlationId, subject, err);
|
|
3204
|
-
msg.term(`Handler error: ${subject}`);
|
|
4451
|
+
reportHandlerError(err);
|
|
3205
4452
|
return void 0;
|
|
3206
4453
|
}
|
|
3207
|
-
if (!
|
|
4454
|
+
if (!isPromiseLike2(pending)) {
|
|
3208
4455
|
if (stopAckExtension !== null) stopAckExtension();
|
|
3209
4456
|
msg.ack();
|
|
3210
4457
|
publishReply(replyTo, correlationId, pending);
|
|
@@ -3215,7 +4462,7 @@ var RpcRouter = class {
|
|
|
3215
4462
|
if (settled) return;
|
|
3216
4463
|
settled = true;
|
|
3217
4464
|
if (stopAckExtension !== null) stopAckExtension();
|
|
3218
|
-
|
|
4465
|
+
abortController.abort();
|
|
3219
4466
|
emitRpcTimeout(subject, correlationId);
|
|
3220
4467
|
msg.term("Handler timeout");
|
|
3221
4468
|
}, timeout);
|
|
@@ -3233,9 +4480,7 @@ var RpcRouter = class {
|
|
|
3233
4480
|
settled = true;
|
|
3234
4481
|
clearTimeout(timeoutId);
|
|
3235
4482
|
if (stopAckExtension !== null) stopAckExtension();
|
|
3236
|
-
|
|
3237
|
-
publishErrorReply(replyTo, correlationId, subject, err);
|
|
3238
|
-
msg.term(`Handler error: ${subject}`);
|
|
4483
|
+
reportHandlerError(err);
|
|
3239
4484
|
}
|
|
3240
4485
|
);
|
|
3241
4486
|
};
|
|
@@ -3267,7 +4512,7 @@ var RpcRouter = class {
|
|
|
3267
4512
|
backlog.push(msg);
|
|
3268
4513
|
if (!backlogWarned && backlog.length >= backlogWarnThreshold) {
|
|
3269
4514
|
backlogWarned = true;
|
|
3270
|
-
|
|
4515
|
+
logger5.warn(
|
|
3271
4516
|
`RPC backlog reached ${backlog.length} messages \u2014 consumer may be falling behind`
|
|
3272
4517
|
);
|
|
3273
4518
|
}
|
|
@@ -3283,7 +4528,7 @@ var RpcRouter = class {
|
|
|
3283
4528
|
}
|
|
3284
4529
|
},
|
|
3285
4530
|
error: (err) => {
|
|
3286
|
-
|
|
4531
|
+
logger5.error("Stream error in RPC router", err);
|
|
3287
4532
|
}
|
|
3288
4533
|
});
|
|
3289
4534
|
}
|
|
@@ -3295,14 +4540,14 @@ var RpcRouter = class {
|
|
|
3295
4540
|
};
|
|
3296
4541
|
|
|
3297
4542
|
// src/shutdown/shutdown.manager.ts
|
|
3298
|
-
import { Logger as
|
|
4543
|
+
import { Logger as Logger17 } from "@nestjs/common";
|
|
3299
4544
|
var ShutdownManager = class {
|
|
3300
4545
|
constructor(connection, eventBus, timeout) {
|
|
3301
4546
|
this.connection = connection;
|
|
3302
4547
|
this.eventBus = eventBus;
|
|
3303
4548
|
this.timeout = timeout;
|
|
3304
4549
|
}
|
|
3305
|
-
logger = new
|
|
4550
|
+
logger = new Logger17("Jetstream:Shutdown");
|
|
3306
4551
|
shutdownPromise;
|
|
3307
4552
|
/**
|
|
3308
4553
|
* Execute the full shutdown sequence.
|
|
@@ -3342,9 +4587,6 @@ var JetstreamModule = class {
|
|
|
3342
4587
|
this.shutdownManager = shutdownManager;
|
|
3343
4588
|
this.strategy = strategy;
|
|
3344
4589
|
}
|
|
3345
|
-
// -------------------------------------------------------------------
|
|
3346
|
-
// forRoot — global module registration
|
|
3347
|
-
// -------------------------------------------------------------------
|
|
3348
4590
|
/**
|
|
3349
4591
|
* Register the JetStream transport globally.
|
|
3350
4592
|
*
|
|
@@ -3371,9 +4613,6 @@ var JetstreamModule = class {
|
|
|
3371
4613
|
]
|
|
3372
4614
|
};
|
|
3373
4615
|
}
|
|
3374
|
-
// -------------------------------------------------------------------
|
|
3375
|
-
// forRootAsync — async global module registration
|
|
3376
|
-
// -------------------------------------------------------------------
|
|
3377
4616
|
/**
|
|
3378
4617
|
* Register the JetStream transport globally with async configuration.
|
|
3379
4618
|
*
|
|
@@ -3402,9 +4641,6 @@ var JetstreamModule = class {
|
|
|
3402
4641
|
]
|
|
3403
4642
|
};
|
|
3404
4643
|
}
|
|
3405
|
-
// -------------------------------------------------------------------
|
|
3406
|
-
// forFeature — per-module client registration
|
|
3407
|
-
// -------------------------------------------------------------------
|
|
3408
4644
|
/**
|
|
3409
4645
|
* Register a lightweight client proxy for a target service.
|
|
3410
4646
|
*
|
|
@@ -3430,9 +4666,6 @@ var JetstreamModule = class {
|
|
|
3430
4666
|
exports: [clientToken]
|
|
3431
4667
|
};
|
|
3432
4668
|
}
|
|
3433
|
-
// -------------------------------------------------------------------
|
|
3434
|
-
// Provider factories
|
|
3435
|
-
// -------------------------------------------------------------------
|
|
3436
4669
|
static createCoreProviders(options) {
|
|
3437
4670
|
return [
|
|
3438
4671
|
{
|
|
@@ -3450,8 +4683,8 @@ var JetstreamModule = class {
|
|
|
3450
4683
|
provide: JETSTREAM_EVENT_BUS,
|
|
3451
4684
|
inject: [JETSTREAM_OPTIONS],
|
|
3452
4685
|
useFactory: (options) => {
|
|
3453
|
-
const
|
|
3454
|
-
return new EventBus(
|
|
4686
|
+
const logger5 = new Logger18("Jetstream:Module");
|
|
4687
|
+
return new EventBus(logger5, options.hooks);
|
|
3455
4688
|
}
|
|
3456
4689
|
},
|
|
3457
4690
|
// Codec — global encode/decode
|
|
@@ -3490,10 +4723,8 @@ var JetstreamModule = class {
|
|
|
3490
4723
|
);
|
|
3491
4724
|
}
|
|
3492
4725
|
},
|
|
3493
|
-
// ---------------------------------------------------------------
|
|
3494
4726
|
// Consumer infrastructure — only created when consumer !== false.
|
|
3495
4727
|
// Providers return null when consumer is disabled (publisher-only mode).
|
|
3496
|
-
// ---------------------------------------------------------------
|
|
3497
4728
|
// PatternRegistry — subject-to-handler mapping
|
|
3498
4729
|
{
|
|
3499
4730
|
provide: PatternRegistry,
|
|
@@ -3529,8 +4760,14 @@ var JetstreamModule = class {
|
|
|
3529
4760
|
// MessageProvider — pull-based message consumption
|
|
3530
4761
|
{
|
|
3531
4762
|
provide: MessageProvider,
|
|
3532
|
-
inject: [
|
|
3533
|
-
|
|
4763
|
+
inject: [
|
|
4764
|
+
JETSTREAM_OPTIONS,
|
|
4765
|
+
JETSTREAM_CONNECTION,
|
|
4766
|
+
JETSTREAM_EVENT_BUS,
|
|
4767
|
+
ConsumerProvider,
|
|
4768
|
+
StreamProvider
|
|
4769
|
+
],
|
|
4770
|
+
useFactory: (options, connection, eventBus, consumerProvider, streamProvider) => {
|
|
3534
4771
|
if (options.consumer === false) return null;
|
|
3535
4772
|
const consumeOptionsMap = /* @__PURE__ */ new Map();
|
|
3536
4773
|
if (options.events?.consume)
|
|
@@ -3540,10 +4777,22 @@ var JetstreamModule = class {
|
|
|
3540
4777
|
if (options.rpc?.mode === "jetstream" && options.rpc.consume) {
|
|
3541
4778
|
consumeOptionsMap.set("cmd" /* Command */, options.rpc.consume);
|
|
3542
4779
|
}
|
|
3543
|
-
const
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
4780
|
+
const derived = deriveOtelAttrs(options);
|
|
4781
|
+
const { otel, serverEndpoint: otelEndpoint, serviceName: otelServiceName } = derived;
|
|
4782
|
+
const consumerRecoveryFn = consumerProvider && streamProvider ? async (kind) => withSelfHealingSpan(
|
|
4783
|
+
otel,
|
|
4784
|
+
{
|
|
4785
|
+
serviceName: otelServiceName,
|
|
4786
|
+
endpoint: otelEndpoint,
|
|
4787
|
+
consumer: consumerProvider.getConsumerName(kind),
|
|
4788
|
+
stream: streamProvider.getStreamName(kind),
|
|
4789
|
+
reason: "consumer not found"
|
|
4790
|
+
},
|
|
4791
|
+
async () => {
|
|
4792
|
+
const jsm = await connection.getJetStreamManager();
|
|
4793
|
+
return consumerProvider.recoverConsumer(jsm, kind);
|
|
4794
|
+
}
|
|
4795
|
+
) : void 0;
|
|
3547
4796
|
return new MessageProvider(connection, eventBus, consumeOptionsMap, consumerRecoveryFn);
|
|
3548
4797
|
}
|
|
3549
4798
|
},
|
|
@@ -3614,7 +4863,8 @@ var JetstreamModule = class {
|
|
|
3614
4863
|
codec,
|
|
3615
4864
|
eventBus,
|
|
3616
4865
|
rpcOptions,
|
|
3617
|
-
ackWaitMap
|
|
4866
|
+
ackWaitMap,
|
|
4867
|
+
options
|
|
3618
4868
|
);
|
|
3619
4869
|
}
|
|
3620
4870
|
},
|
|
@@ -3717,9 +4967,6 @@ var JetstreamModule = class {
|
|
|
3717
4967
|
}
|
|
3718
4968
|
];
|
|
3719
4969
|
}
|
|
3720
|
-
// -------------------------------------------------------------------
|
|
3721
|
-
// Lifecycle hooks
|
|
3722
|
-
// -------------------------------------------------------------------
|
|
3723
4970
|
/**
|
|
3724
4971
|
* Gracefully shut down the transport on application termination.
|
|
3725
4972
|
*/
|
|
@@ -3738,6 +4985,7 @@ JetstreamModule = __decorateClass([
|
|
|
3738
4985
|
__decorateParam(1, Inject(JetstreamStrategy))
|
|
3739
4986
|
], JetstreamModule);
|
|
3740
4987
|
export {
|
|
4988
|
+
ConsumeKind,
|
|
3741
4989
|
DEFAULT_BROADCAST_CONSUMER_CONFIG,
|
|
3742
4990
|
DEFAULT_BROADCAST_STREAM_CONFIG,
|
|
3743
4991
|
DEFAULT_COMMAND_CONSUMER_CONFIG,
|
|
@@ -3753,6 +5001,7 @@ export {
|
|
|
3753
5001
|
DEFAULT_ORDERED_STREAM_CONFIG,
|
|
3754
5002
|
DEFAULT_RPC_TIMEOUT,
|
|
3755
5003
|
DEFAULT_SHUTDOWN_TIMEOUT,
|
|
5004
|
+
DEFAULT_TRACES,
|
|
3756
5005
|
JETSTREAM_CODEC,
|
|
3757
5006
|
JETSTREAM_CONNECTION,
|
|
3758
5007
|
JETSTREAM_OPTIONS,
|
|
@@ -3764,15 +5013,18 @@ export {
|
|
|
3764
5013
|
JetstreamRecord,
|
|
3765
5014
|
JetstreamRecordBuilder,
|
|
3766
5015
|
JetstreamStrategy,
|
|
5016
|
+
JetstreamTrace,
|
|
3767
5017
|
JsonCodec,
|
|
3768
5018
|
MIN_METADATA_TTL,
|
|
3769
5019
|
MessageKind,
|
|
3770
5020
|
MsgpackCodec,
|
|
3771
5021
|
NatsErrorCode,
|
|
3772
5022
|
PatternPrefix,
|
|
5023
|
+
PublishKind,
|
|
3773
5024
|
RESERVED_HEADERS,
|
|
3774
5025
|
RpcContext,
|
|
3775
5026
|
StreamKind,
|
|
5027
|
+
TRACER_NAME,
|
|
3776
5028
|
TransportEvent,
|
|
3777
5029
|
buildBroadcastSubject,
|
|
3778
5030
|
buildSubject,
|