Transport configuration
Overview
Section titled “Overview”The transport is the wire-level pair (ITransportProducer + ITransportConsumer) the bus uses to send and receive envelopes. It is pluggable: any object that satisfies those interfaces will work. The supported, batteries-included implementation lives in @serviceconnect/rabbitmq and is configured via RabbitMQTransportOptions.
This page documents the RabbitMQ transport. Replacing the transport (in-memory test double, NATS, Kafka, etc.) is covered under extension points.
Import
Section titled “Import”import { createRabbitMQTransport, rabbitMQWithRegistry } from '@serviceconnect/rabbitmq';Signatures
Section titled “Signatures”export function createRabbitMQTransport(opts: RabbitMQTransportOptions): RabbitMQTransport;
export function rabbitMQWithRegistry( opts: Omit<RabbitMQTransportOptions, 'parentsOf'>, registry: IMessageTypeRegistry,): RabbitMQTransport;rabbitMQWithRegistry is a convenience wrapper: it wires parentsOf from an IMessageTypeRegistry so polymorphic publishes fan out to every registered ancestor exchange. Reach for it whenever you have polymorphic messages registered on a registry; otherwise createRabbitMQTransport is enough.
RabbitMQTransportOptions
Section titled “RabbitMQTransportOptions”export interface RabbitMQTransportOptions { url: string; tls?: boolean | import('node:tls').ConnectionOptions; onConnectionError?: (error: Error, role: 'producer' | 'consumer') => void; acquireTimeout?: number; heartbeat?: number; retryLow?: number; retryHigh?: number; connectionName?: string; parentsOf?: (typeName: string) => readonly string[]; producer?: { publishConfirmTimeoutMs?: number; maxAttempts?: number; maxMessageSize?: number; }; consumer?: { concurrency?: number; prefetch?: number; retryDelay?: number; maxRetries?: number; errorQueue?: string | null; auditQueue?: string; auditEnabled?: boolean; deadLetterUnhandled?: boolean; queueArguments?: Record<string, unknown>; retryQueueArguments?: Record<string, unknown>; };}Connection
Section titled “Connection”url(required) —string. AMQP connection string. Supports the standardamqp://user:pass@host:port/vhostform and the comma-separated cluster shorthandamqp://user:pass@host-1,host-2,host-3:5672/vhost.tls(optional) —boolean | import('node:tls').ConnectionOptions. Whentrue, connect over TLS (amqps) with defaults. Pass an object to forward custom settings to Node’s TLS layer (ca/cert/key/pfx, etc.) for mutual-TLS or private-CA brokers.onConnectionError(optional) —(error: Error, role: 'producer' | 'consumer') => void. Callback invoked on a connection-level error;roletells you whether the failing connection is the producer’s or the consumer’s.acquireTimeout(optional) —number(ms). How long the underlying client will wait for a channel or connection before throwing.heartbeat(optional) —number(s). AMQP heartbeat interval. Smaller values detect dead peers faster at the cost of more idle traffic.retryLow(optional) —number(ms). Lower bound for connect-retry backoff.retryHigh(optional) —number(ms). Upper bound for connect-retry backoff.connectionName(optional) —string. A base name for the connections shown in the RabbitMQ management UI. The transport opens two connections and appends a per-role suffix, so the labels actually shown are<connectionName>.producerand<connectionName>.consumer. When unset the base defaults toserviceconnect. Set it to the service name so operators can tell connections apart.parentsOf(optional) —(typeName: string) => readonly string[]. Returns the ancestor message-type names for a given type name. Used for polymorphic publishes. Set this manually only if you are not usingrabbitMQWithRegistry.
producer.*
Section titled “producer.*”publishConfirmTimeoutMs(optional) —number(ms). Reserved / currently dormant. The option is accepted and resolved (default30_000) but is not wired into the publish path: the publisher is created with publisher-confirms enabled (confirm: true) andmaxAttemptsonly, and the underlying client uses its own confirm timeout. Setting this value has no effect today.maxAttempts(optional) —number. How many times the producer retries a publish on transient failures. Default3.maxMessageSize(optional) —number(bytes). Hard cap on a single serialised envelope. Default134_217_728(128 MiB).
consumer.*
Section titled “consumer.*”concurrency(optional) —number. Maximum number of messages this consumer processes simultaneously. Default unset/unbounded —rabbitmq-clientprocesses up toprefetchmessages at once. This is distinct fromprefetch:prefetchgoverns how many unacknowledged messages the broker delivers, whileconcurrencycaps how many are handled in parallel. Set it to1for strict, one-at-a-time, in-order processing — e.g. ordered saga handling where a message and its follow-ups must run in publish order.prefetch(optional) —number. Per-channel prefetch count — the maximum number of unacknowledged messages the broker will deliver to this consumer at once. Default100.retryDelay(optional) —number(ms). Delay before a failed message is redelivered to the main queue. Default3000.maxRetries(optional) —number. The total number of delivery attempts before routing the message to the error queue (the initial delivery plusmaxRetries - 1redeliveries). The boundary is strict, somaxRetries=3means 3 attempts in total — 1 initial delivery plus 2 redeliveries — and the message is dead-lettered on the 3rd failure;maxRetries=1means no retries. Default3.errorQueue(optional) —string | null. Name of the error queue that exhausted messages are routed to. Default'errors'. Set tonullto disable error-queue routing entirely (failed messages will be dead-lettered or dropped perdeadLetterUnhandled).auditQueue(optional) —string. Name of the audit queue that mirrors every successfully-handled message when auditing is on. Not-handled, retried, and errored messages are not audited. Default'audit'.auditEnabled(optional) —boolean. Whether to mirror consumed messages toauditQueue. Defaultfalse.deadLetterUnhandled(optional) —boolean. Whentrue, messages with no registered handler are dead-lettered instead of acked-and-dropped. Defaultfalse.queueArguments(optional) —Record<string, unknown>. Extra arguments passed when the consumer declares its main queue (e.g.{ 'x-queue-type': 'quorum' },{ 'x-message-ttl': 60_000 }).retryQueueArguments(optional) —Record<string, unknown>. Extra arguments passed when the consumer declares its retry queue.
Example
Section titled “Example”import { rabbitMQWithRegistry } from '@serviceconnect/rabbitmq';import { createMessageTypeRegistry } from '@serviceconnect/core';
const registry = createMessageTypeRegistry();const transport = rabbitMQWithRegistry( { url: 'amqp://app:secret@rabbit-1,rabbit-2,rabbit-3:5672/%2F?heartbeat=10', connectionName: 'orders-service', consumer: { prefetch: 32, maxRetries: 5, retryDelay: 2000, auditEnabled: true, }, producer: { maxMessageSize: 8 * 1024 * 1024, }, }, registry,);Runtime introspection
Section titled “Runtime introspection”The transport returns objects rather than raw plumbing, so health checks and dashboards can read live state without reaching into the AMQP client:
RabbitMQProducer— the wire-level producer the bus uses forpublish/send. ExposesisHealthy: boolean(used byproducerConnectivity) andsnapshot(): ProducerSnapshotfor diagnostics.ProducerSnapshot— point-in-time view of producer state: connection status, last publish-confirm latency, in-flight publish count. Stable shape, safe to log on every health probe.RabbitMQConsumer— the wire-level consumer. ExposesisConnected,isStopped,isCancelledByBroker, andsnapshot(): ConsumerSnapshot. The last-consume timestamp (lastConsumedAt) is not a property on the consumer itself; it is a field on theConsumerSnapshotreturned bysnapshot().ConsumerSnapshot— point-in-time view of consumer state: connection status, prefetch counters, last-consume timestamps. Same observability contract as the producer.
Application code rarely names these types; they are useful when you are writing a transport-aware health check or custom telemetry adapter.
Transport-specific errors
Section titled “Transport-specific errors”The RabbitMQ producer raises a small set of typed errors that callers can catch by class:
RabbitMQPayloadTooLargeError— thrown by any producer write path (producer.publish,producer.send, andproducer.sendBytes) when the serialised envelope exceedsproducer.maxMessageSize. The error message includes both the actual byte count and the configured cap, so the caller can either chunk via streaming or raise the limit. This is a producer-side guard; the broker does not validate the size.RabbitMQPublishConfirmTimeoutError— exported for forward-compatibility but not currently thrown by the transport. Publish-confirm timeouts are not surfaced as this error today (the option that would drive it,producer.publishConfirmTimeoutMs, is itself dormant — see above).RabbitMQTopologyMismatchError— exported for forward-compatibility but not currently thrown by the transport. On a topology conflict (aPRECONDITION_FAILED/ inequivalent-arguments declare), the consumer does not throw: it silently falls back to a passive queue declare that just asserts the existing queue is present.
The inbound side exposes one legacy type alias:
RabbitMQMessage— a deprecated alias of the coreMessagetype (export type RabbitMQMessage = Message), kept only for legacy probe/smoke tests. It is not a distinct wire-level envelope type and is not yielded byRabbitMQConsumer: the consumer maps AMQP messages to the framework’sEnvelopevia its internaltoEnvelopemapping, and ordinary handlers receive thatEnvelope.