@relaybus/rabbitmq 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +236 -2
- package/dist/index.cjs +1113 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +281 -0
- package/dist/index.d.ts +281 -0
- package/dist/index.js +1105 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/abortable-sleep.ts","../src/connection-supervisor.ts","../src/redelivery.ts","../src/options.ts","../src/topology.ts","../src/json-payload.ts","../src/wire-format.ts","../src/queue-consumer.ts","../src/serial-queue.ts","../src/rabbitmq-transport.ts"],"names":["RelayBusError","NonRetryableError","toErrorInfo","computeRetryDelay","ConfigurationError","createRetryPolicy","toMilliseconds","isRetryableError","delayMs"],"mappings":"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","file":"index.cjs","sourcesContent":["import { NonRetryableError, RelayBusError } from '@relaybus/core';\n\n/**\n * The broker cannot take or confirm a message right now: the transport is not\n * connected, was closed, lost its channel, or the confirm did not arrive in time.\n * Always retryable; the outbox keeps the delivery and tries again.\n */\nexport class RabbitMqUnavailableError extends RelayBusError {}\n\n/** The broker negatively acknowledged a published message. Retryable. */\nexport class RabbitMqPublishRejectedError extends RelayBusError {}\n\n/**\n * The broker accepted the message but no queue is bound to its routing key, so\n * it would have been discarded. Retryable: it succeeds once a consumer binds.\n */\nexport class UnroutableMessageError extends RelayBusError {}\n\n/** A received message is not a valid relaybus CloudEvent. It is dead-lettered. */\nexport class MalformedMessageError extends RelayBusError {}\n\n/**\n * The payload of an event cannot be represented as JSON without losing or\n * changing data (`undefined`, functions, symbols, BigInt, NaN, Infinity, Dates,\n * Maps, class instances, cycles). Never retried: the payload will not change.\n */\nexport class UnserializablePayloadError extends NonRetryableError {\n override name = 'UnserializablePayloadError';\n}\n\n/**\n * A value exceeds a protocol limit of AMQP 0-9-1, for example an event id or a\n * routing key longer than the 255 bytes of a short string. Never retried.\n */\nexport class AmqpLimitExceededError extends NonRetryableError {\n override name = 'AmqpLimitExceededError';\n}\n","/** Resolves after `milliseconds`, or as soon as `signal` aborts (immediately when it already has). Never rejects. */\nexport function abortableSleep(milliseconds: number, signal: AbortSignal): Promise<void> {\n if (signal.aborted) {\n return Promise.resolve();\n }\n return new Promise((resolve) => {\n const finish = (): void => {\n clearTimeout(timer);\n signal.removeEventListener('abort', finish);\n resolve();\n };\n const timer = setTimeout(finish, milliseconds);\n signal.addEventListener('abort', finish, { once: true });\n });\n}\n","import {\n computeRetryDelay,\n toErrorInfo,\n type RelayBusLogger,\n type RetryPolicy,\n} from '@relaybus/core';\nimport { abortableSleep } from './abortable-sleep.js';\nimport type { AmqpConnection } from './amqp-types.js';\nimport { RabbitMqUnavailableError } from './errors.js';\n\nexport interface ConnectionSupervisorSettings {\n readonly connect: () => Promise<AmqpConnection>;\n /** Backoff between attempts, or undefined to never reconnect. */\n readonly reconnect: RetryPolicy | undefined;\n /** Creates channels and topology on a fresh connection. A rejection discards the connection. */\n readonly onConnected: (connection: AmqpConnection) => Promise<void>;\n /** The connection is gone or was discarded: drop everything that referenced it. */\n readonly onDisconnected: () => void;\n readonly logger: RelayBusLogger;\n readonly random: () => number;\n}\n\n/**\n * Owns the broker connection. amqplib does not reconnect, so after a connection\n * loss this class retries with capped, jittered backoff until `onConnected`\n * succeeds, and `close` stops it. It reports ready only once `onConnected` has\n * finished, so callers never use half-built channels.\n */\nexport class ConnectionSupervisor {\n readonly #settings: ConnectionSupervisorSettings;\n readonly #stop = new AbortController();\n #current: AmqpConnection | undefined;\n #ready = false;\n #started = false;\n #closed = false;\n #reconnecting: Promise<void> | undefined;\n\n constructor(settings: ConnectionSupervisorSettings) {\n this.#settings = settings;\n }\n\n /** True while a connection is open and `onConnected` has completed for it. */\n isConnected(): boolean {\n return this.#ready;\n }\n\n /**\n * Connects once. When that fails it rejects if `failOnError`, otherwise it\n * resolves and keeps trying in the background. Does nothing when already started.\n */\n async start(failOnError: boolean): Promise<void> {\n if (this.#started) {\n return;\n }\n if (this.#closed) {\n throw new RabbitMqUnavailableError('[ConnectionSupervisor](start) Transport is closed');\n }\n try {\n await this.#establish();\n this.#started = true;\n } catch (error) {\n if (failOnError) {\n throw error;\n }\n this.#settings.logger.warn(\n `[ConnectionSupervisor](start) Broker unreachable, retrying in the background | error=${toErrorInfo(error).message}`,\n );\n this.#started = true;\n this.#startReconnecting();\n }\n }\n\n /**\n * Drops the current connection because one of its channels failed, then\n * reconnects. Closing the channel alone would leave topology half-restored.\n */\n recover(reason: string): void {\n const connection = this.#current;\n if (connection === undefined) {\n return;\n }\n this.#handleLoss(connection, reason);\n connection.close().catch(() => undefined);\n }\n\n /**\n * Stops reconnecting, runs `beforeDisconnect` while the connection is still\n * open (to drain consumers) and closes the connection.\n */\n async close(beforeDisconnect: () => Promise<void>): Promise<void> {\n this.#closed = true;\n this.#stop.abort();\n await this.#reconnecting;\n try {\n await beforeDisconnect();\n } finally {\n const connection = this.#current;\n this.#current = undefined;\n this.#ready = false;\n await connection?.close().catch(() => undefined);\n }\n }\n\n async #establish(): Promise<void> {\n const connection = await this.#settings.connect();\n connection.on('error', (error: Error) => {\n this.#settings.logger.warn(\n `[ConnectionSupervisor](establish) Connection error | error=${error.message}`,\n );\n });\n connection.on('close', (error?: Error) => {\n this.#handleLoss(connection, error?.message ?? 'closed by peer');\n });\n this.#current = connection;\n try {\n await this.#settings.onConnected(connection);\n if (this.#current !== connection) {\n throw new RabbitMqUnavailableError(\n 'Connection was lost while the topology was being set up',\n );\n }\n } catch (error) {\n await this.#discard(connection);\n throw error;\n }\n this.#ready = true;\n }\n\n async #discard(connection: AmqpConnection): Promise<void> {\n if (this.#current === connection) {\n this.#current = undefined;\n }\n this.#settings.onDisconnected();\n await connection.close().catch(() => undefined);\n }\n\n #handleLoss(connection: AmqpConnection, reason: string): void {\n if (connection !== this.#current) {\n return;\n }\n this.#current = undefined;\n this.#ready = false;\n this.#settings.logger.warn(\n `[ConnectionSupervisor](handleLoss) Connection lost | reason=${reason}`,\n );\n this.#settings.onDisconnected();\n this.#startReconnecting();\n }\n\n #startReconnecting(): void {\n if (\n this.#settings.reconnect === undefined ||\n this.#closed ||\n !this.#started ||\n this.#reconnecting !== undefined\n ) {\n return;\n }\n const policy = this.#settings.reconnect;\n this.#reconnecting = this.#reconnectUntilConnected(policy).finally(() => {\n this.#reconnecting = undefined;\n });\n }\n\n async #reconnectUntilConnected(policy: RetryPolicy): Promise<void> {\n for (let attempt = 1; !this.#closed; attempt += 1) {\n const delayMs = computeRetryDelay(policy, attempt, this.#settings.random);\n this.#settings.logger.log(\n `[ConnectionSupervisor](reconnect) Reconnecting | attempt=${attempt} delayMs=${delayMs}`,\n );\n await abortableSleep(delayMs, this.#stop.signal);\n if (this.#closed) {\n return;\n }\n try {\n await this.#establish();\n this.#settings.logger.log(\n `[ConnectionSupervisor](reconnect) Reconnected | attempt=${attempt}`,\n );\n return;\n } catch (error) {\n this.#settings.logger.warn(\n `[ConnectionSupervisor](reconnect) Attempt failed | attempt=${attempt} error=${toErrorInfo(error).message}`,\n );\n }\n }\n }\n}\n","import { ConfigurationError, type RetryPolicy } from '@relaybus/core';\nimport type { AmqpMessage, AmqpPublishOptions } from './amqp-types.js';\n\n/** Number of delayed redeliveries a message went through. Set on every retry copy. */\nexport const REDELIVERIES_HEADER = 'x-relaybus-redeliveries';\n/** Epoch milliseconds of the first failure that needed a delayed redelivery. */\nexport const FIRST_FAILURE_HEADER = 'x-relaybus-first-failure-at';\n/** Why a message was moved to the dead-letter queue by the consumer. */\nexport const DEAD_LETTER_REASON_HEADER = 'x-relaybus-dead-letter-reason';\n\nconst RELAYBUS_STATE_HEADERS: readonly string[] = [REDELIVERIES_HEADER, FIRST_FAILURE_HEADER];\n/** Counters the broker stamps on its own redeliveries; they must not travel in a copy. */\nconst BROKER_COUNTER_HEADERS: readonly string[] = ['x-delivery-count', 'x-acquired-count'];\nconst MAXIMUM_LADDER_TIERS = 16;\n\n/**\n * The fixed delays of the retry queues, ascending: the policy's delay grown by\n * its factor until the cap. Each tier is its own queue with a queue-level TTL,\n * so messages in one queue always expire in arrival order; one queue with\n * mixed per-message TTLs would let a long delay hold back shorter ones.\n *\n * @throws {ConfigurationError} the policy has no usable delays or too many tiers\n */\nexport function buildRetryLadder(policy: RetryPolicy): readonly number[] {\n if (policy.initialDelayMs < 1) {\n throw new ConfigurationError('redelivery.initialDelay must be at least 1ms');\n }\n const tiers: number[] = [];\n let delay = policy.initialDelayMs;\n for (;;) {\n const tier = Math.round(Math.min(delay, policy.maxDelayMs));\n tiers.push(tier);\n if (tier >= policy.maxDelayMs || policy.factor === 1) {\n return tiers;\n }\n if (tiers.length === MAXIMUM_LADDER_TIERS) {\n throw new ConfigurationError(\n `redelivery needs more than ${MAXIMUM_LADDER_TIERS} retry queues; raise redelivery.factor or lower redelivery.maxDelay`,\n );\n }\n delay *= policy.factor;\n }\n}\n\n/**\n * Maps a jittered delay onto the ladder. A delay between two tiers goes to the\n * upper one with the probability that keeps the expected delay equal to\n * `delayMs`, so jitter still spreads a cohort of failures across tiers.\n */\nexport function chooseRetryTier(\n ladder: readonly number[],\n delayMs: number,\n random: () => number,\n): number {\n const upperIndex = ladder.findIndex((tier) => tier >= delayMs);\n if (upperIndex === -1) {\n return ladder.at(-1)!;\n }\n if (upperIndex === 0) {\n return ladder[0]!;\n }\n const lower = ladder[upperIndex - 1]!;\n const upper = ladder[upperIndex]!;\n return random() < (delayMs - lower) / (upper - lower) ? upper : lower;\n}\n\n/** Reads a non-negative integer that a copy carries as a header (string or number). */\nexport function readCounterHeader(message: AmqpMessage, name: string): number | undefined {\n // A message that decoded has headers: `cloudEvents:specversion` is required.\n const value = message.properties.headers![name];\n const parsed = typeof value === 'string' && /^\\d+$/.test(value) ? Number(value) : value;\n return typeof parsed === 'number' && Number.isSafeInteger(parsed) && parsed >= 0\n ? parsed\n : undefined;\n}\n\n/**\n * A byte-faithful copy of a received message for publishing to another queue:\n * same body and properties, headers carried over except the broker's delivery\n * counters and relaybus' own redelivery state, then `headerChanges` applied.\n */\nexport function copyForRepublish(\n message: AmqpMessage,\n headerChanges: Readonly<Record<string, string>>,\n): { content: Buffer; options: AmqpPublishOptions } {\n const { properties } = message;\n const headers: Record<string, unknown> = { ...properties.headers };\n for (const name of [\n ...RELAYBUS_STATE_HEADERS,\n DEAD_LETTER_REASON_HEADER,\n ...BROKER_COUNTER_HEADERS,\n ]) {\n delete headers[name];\n }\n Object.assign(headers, headerChanges);\n return {\n content: message.content,\n options: {\n contentType:\n typeof properties.contentType === 'string' ? properties.contentType : 'application/json',\n persistent: true,\n ...(typeof properties.messageId === 'string' ? { messageId: properties.messageId } : {}),\n ...(typeof properties.type === 'string' ? { type: properties.type } : {}),\n ...(typeof properties.appId === 'string' ? { appId: properties.appId } : {}),\n ...(typeof properties.correlationId === 'string'\n ? { correlationId: properties.correlationId }\n : {}),\n ...(typeof properties.timestamp === 'number' ? { timestamp: properties.timestamp } : {}),\n headers,\n },\n };\n}\n","import {\n ConfigurationError,\n createRetryPolicy,\n toMilliseconds,\n type Duration,\n type RelayBusLogger,\n type RetryPolicy,\n type RetryPolicyOptions,\n} from '@relaybus/core';\nimport type { AmqpConnection } from './amqp-types.js';\nimport { buildRetryLadder } from './redelivery.js';\n\n/** Connection settings accepted by `amqplib.connect`, given as an object instead of a URL. */\nexport interface BrokerConnectionSettings {\n readonly protocol?: string;\n readonly hostname?: string;\n readonly port?: number;\n readonly username?: string;\n readonly password?: string;\n readonly vhost?: string;\n /** Seconds. See \"Operational notes\" in the README for the heartbeat defaults of each amqplib version. */\n readonly heartbeat?: number;\n}\n\n/** Backoff between reconnect attempts. Attempts are unlimited. */\nexport type ReconnectOptions = Pick<\n RetryPolicyOptions,\n 'initialDelay' | 'factor' | 'maxDelay' | 'jitter'\n>;\n\n/**\n * Delayed redelivery of messages whose handler keeps failing. Each failed\n * delivery goes to a retry queue and returns to the main queue after a growing\n * delay, so an outage of the handler's dependency is waited out instead of\n * burning through delivery attempts.\n */\nexport type RedeliveryOptions = Pick<\n RetryPolicyOptions,\n 'initialDelay' | 'factor' | 'maxDelay' | 'jitter'\n> & {\n /**\n * How long a message may keep failing, counted from its first delayed\n * redelivery, before it is dead-lettered. Default `'1h'`.\n */\n readonly maxAge?: Duration;\n};\n\nexport interface RabbitMqTransportOptions {\n /** Name referenced by routes and subscriptions. Default `'rabbitmq'`. */\n readonly name?: string;\n /**\n * Broker location, for example `amqp://user:pass@host:5672/vhost?heartbeat=30`.\n * Give exactly one of `url` and `connect`.\n */\n readonly url?: string | BrokerConnectionSettings;\n /**\n * Opens one connection. Called again after every connection loss. Use it for\n * TLS options, custom credentials or an alternative amqplib instance.\n */\n readonly connect?: () => Promise<AmqpConnection>;\n /** Topic exchange events are published to. Durable, created when missing. Default `'relaybus'`. */\n readonly exchange?: string;\n /**\n * Unacknowledged messages the consumer holds, which is also its concurrency.\n * Default 50, or 1 when `ordered`.\n */\n readonly prefetch?: number;\n /** Prefix of derived queue names. Default `'relaybus'`. */\n readonly queuePrefix?: string;\n /**\n * Consumer group: services sharing it share one queue and split the messages,\n * services with different groups each receive every message. The queue is\n * `<queuePrefix>.<consumerGroup>`. Required when subscribing, unless `queue` is set.\n */\n readonly consumerGroup?: string;\n /** Explicit queue name. Overrides `queuePrefix` and `consumerGroup`. */\n readonly queue?: string;\n /** Exchange poison messages are dead-lettered to. Default `'<exchange>.dead'`. */\n readonly deadLetterExchange?: string;\n /** Queue that keeps dead-lettered messages for inspection. Default `'<queue>.dead'`. */\n readonly deadLetterQueue?: string;\n /**\n * Quorum queue `x-delivery-limit`: deliveries after which the broker itself\n * dead-letters a message. Failing handlers do not consume it (they use\n * `redelivery`); it only stops a message that crashes the consumer or its\n * channel again and again. Default 10.\n */\n readonly deliveryLimit?: number;\n /**\n * Handler attempts on the same delivery, with backoff, before the message is\n * scheduled for delayed redelivery. Absorbs short blips without a broker round\n * trip. Default: 3 attempts, 200 ms initial delay, factor 2, 5 s cap, equal jitter.\n */\n readonly handlerRetry?: RetryPolicyOptions;\n /**\n * Delayed redelivery after `handlerRetry` is spent. Default: 2 s initial\n * delay, factor 2, 5 min cap, equal jitter, dead-lettered after 1 h of\n * failing (about 18 redeliveries). Delays are quantized to the retry queues,\n * one per step of the exponential ladder (9 queues with the defaults).\n * Ignored when `ordered`, where the same delays are waited in place.\n */\n readonly redelivery?: RedeliveryOptions;\n /**\n * Consume the queue strictly in order: a single active consumer across all\n * replicas, one message at a time, a failing message is retried in place\n * (blocking the queue) instead of being delayed. Needed when\n * `EventEnvelope.key` order matters; costs throughput, because one handler\n * runs at a time. Default false: handlers run concurrently and a delayed\n * redelivery overtakes later messages, so order is not preserved.\n */\n readonly ordered?: boolean;\n /** Reconnect backoff, or `false` to never reconnect. Default: 500 ms initial, factor 2, 30 s cap, equal jitter. */\n readonly reconnect?: ReconnectOptions | false;\n /**\n * When true (default) `connect()` rejects if the broker is unreachable, which\n * fails startup. When false it resolves and keeps trying in the background.\n */\n readonly failOnConnectError?: boolean;\n /**\n * When false (default) a message that no queue is bound to makes `publish`\n * reject. When true it resolves and the broker silently discards the message.\n */\n readonly allowUnroutable?: boolean;\n /** How long `publish` waits for the broker confirm. Default `'30s'`. */\n readonly publishTimeout?: Duration;\n /** How long `close` waits for running handlers. Default `'30s'`. */\n readonly shutdownTimeout?: Duration;\n /** Default: `console`. */\n readonly logger?: RelayBusLogger;\n /** Random source for jitter. Default `Math.random`. Intended for tests. */\n readonly random?: () => number;\n}\n\nexport interface ResolvedTransportSettings {\n readonly name: string;\n readonly connect: () => Promise<AmqpConnection>;\n readonly exchange: string;\n readonly prefetch: number;\n readonly queuePrefix: string;\n readonly consumerGroup: string | undefined;\n readonly queue: string | undefined;\n readonly deadLetterExchange: string;\n readonly deadLetterQueue: string | undefined;\n readonly deliveryLimit: number;\n readonly handlerRetry: RetryPolicy;\n readonly redelivery: RetryPolicy;\n /** Fixed delays of the retry queues; empty when `ordered`. */\n readonly retryLadder: readonly number[];\n readonly redeliveryMaxAgeMs: number;\n readonly ordered: boolean;\n readonly reconnect: RetryPolicy | undefined;\n readonly failOnConnectError: boolean;\n readonly allowUnroutable: boolean;\n readonly publishTimeoutMs: number;\n readonly shutdownTimeoutMs: number;\n readonly logger: RelayBusLogger;\n readonly random: () => number;\n}\n\nconst DEFAULT_HANDLER_RETRY: RetryPolicy = {\n attempts: 3,\n initialDelayMs: 200,\n factor: 2,\n maxDelayMs: 5_000,\n jitter: 'equal',\n retryIf: undefined,\n};\n\nconst DEFAULT_REDELIVERY: RetryPolicy = {\n attempts: Number.POSITIVE_INFINITY,\n initialDelayMs: 2_000,\n factor: 2,\n maxDelayMs: 300_000,\n jitter: 'equal',\n retryIf: undefined,\n};\n\nconst DEFAULT_REDELIVERY_MAX_AGE = '1h';\n\nconst DEFAULT_RECONNECT: RetryPolicy = {\n attempts: 1,\n initialDelayMs: 500,\n factor: 2,\n maxDelayMs: 30_000,\n jitter: 'equal',\n retryIf: undefined,\n};\n\n/** Validates the options and applies defaults. Throws `ConfigurationError`. */\nexport function resolveSettings(options: RabbitMqTransportOptions): ResolvedTransportSettings {\n const exchange = nonEmpty(options.exchange ?? 'relaybus', 'exchange');\n const failOnConnectError = options.failOnConnectError ?? true;\n if (!failOnConnectError && options.reconnect === false) {\n throw new ConfigurationError(\n 'failOnConnectError=false needs reconnect enabled, otherwise the transport would never connect',\n );\n }\n const ordered = options.ordered ?? false;\n const prefetch = positiveInteger(options.prefetch ?? (ordered ? 1 : 50), 'prefetch');\n if (ordered && prefetch !== 1) {\n throw new ConfigurationError(`ordered consumption needs prefetch 1, received ${prefetch}`);\n }\n const redelivery = createRetryPolicy(options.redelivery, DEFAULT_REDELIVERY);\n return {\n name: nonEmpty(options.name ?? 'rabbitmq', 'name'),\n connect: resolveConnect(options),\n exchange,\n prefetch,\n queuePrefix: nonEmpty(options.queuePrefix ?? 'relaybus', 'queuePrefix'),\n consumerGroup: optionalNonEmpty(options.consumerGroup, 'consumerGroup'),\n queue: optionalNonEmpty(options.queue, 'queue'),\n deadLetterExchange: nonEmpty(\n options.deadLetterExchange ?? `${exchange}.dead`,\n 'deadLetterExchange',\n ),\n deadLetterQueue: optionalNonEmpty(options.deadLetterQueue, 'deadLetterQueue'),\n deliveryLimit: positiveInteger(options.deliveryLimit ?? 10, 'deliveryLimit'),\n handlerRetry: createRetryPolicy(options.handlerRetry, DEFAULT_HANDLER_RETRY),\n redelivery,\n retryLadder: ordered ? [] : buildRetryLadder(redelivery),\n redeliveryMaxAgeMs: positiveDuration(\n options.redelivery?.maxAge ?? DEFAULT_REDELIVERY_MAX_AGE,\n 'redelivery.maxAge',\n ),\n ordered,\n reconnect: resolveReconnect(options.reconnect),\n failOnConnectError,\n allowUnroutable: options.allowUnroutable ?? false,\n publishTimeoutMs: positiveDuration(options.publishTimeout ?? '30s', 'publishTimeout'),\n shutdownTimeoutMs: toMilliseconds(options.shutdownTimeout ?? '30s', 'shutdownTimeout'),\n logger: options.logger ?? console,\n random: options.random ?? Math.random,\n };\n}\n\n/** `<queuePrefix>.<consumerGroup>`, or the explicit queue name. */\nexport function resolveQueueName(settings: ResolvedTransportSettings): string {\n if (settings.queue !== undefined) {\n return settings.queue;\n }\n if (settings.consumerGroup === undefined) {\n throw new ConfigurationError(\n `Transport '${settings.name}' needs 'consumerGroup' or 'queue' to subscribe`,\n );\n }\n return `${settings.queuePrefix}.${settings.consumerGroup}`;\n}\n\nfunction resolveConnect(options: RabbitMqTransportOptions): () => Promise<AmqpConnection> {\n const { url, connect } = options;\n if ((url === undefined) === (connect === undefined)) {\n throw new ConfigurationError(\"Give exactly one of 'url' and 'connect'\");\n }\n if (connect !== undefined) {\n return connect;\n }\n return async () => {\n const amqplib = await import('amqplib');\n return amqplib.connect(url!);\n };\n}\n\nfunction resolveReconnect(\n reconnect: ReconnectOptions | false | undefined,\n): RetryPolicy | undefined {\n if (reconnect === false) {\n return undefined;\n }\n return createRetryPolicy({ ...reconnect, attempts: 1 }, DEFAULT_RECONNECT);\n}\n\nfunction nonEmpty(value: string, name: string): string {\n if (value.length === 0) {\n throw new ConfigurationError(`${name} must not be empty`);\n }\n return value;\n}\n\nfunction optionalNonEmpty(value: string | undefined, name: string): string | undefined {\n return value === undefined ? undefined : nonEmpty(value, name);\n}\n\nfunction positiveInteger(value: number, name: string): number {\n if (!Number.isInteger(value) || value < 1) {\n throw new ConfigurationError(`${name} must be a positive integer, received ${value}`);\n }\n return value;\n}\n\nfunction positiveDuration(value: Duration, name: string): number {\n const milliseconds = toMilliseconds(value, name);\n if (milliseconds === 0) {\n throw new ConfigurationError(`${name} must be greater than zero`);\n }\n return milliseconds;\n}\n","import type { AmqpChannel } from './amqp-types.js';\n\n/** Names of the broker objects a subscribing transport owns. */\nexport interface ConsumerTopology {\n readonly exchange: string;\n readonly queue: string;\n readonly deadLetterExchange: string;\n readonly deadLetterQueue: string;\n readonly deliveryLimit: number;\n /** Single active consumer, so the queue is consumed strictly in order. */\n readonly ordered: boolean;\n /** TTLs of the retry queues, ascending; empty when ordered. */\n readonly retryDelaysMs: readonly number[];\n /** Routing-key patterns the queue is bound with. */\n readonly destinations: readonly string[];\n}\n\n/** Name of the retry queue that holds messages for `delayMs` before returning them to `queue`. */\nexport function retryQueueName(queue: string, delayMs: number): string {\n return `${queue}.retry.${delayMs}`;\n}\n\n/** Declares the durable topic exchange events are published to. Idempotent. */\nexport async function assertExchange(channel: AmqpChannel, exchange: string): Promise<void> {\n await channel.assertExchange(exchange, 'topic', { durable: true });\n}\n\n/**\n * Declares the consumer side, all durable quorum queues and idempotent:\n *\n * - the main queue with a dead-letter exchange, `x-dead-letter-strategy`\n * `at-least-once` (which requires `x-overflow` `reject-publish`),\n * `x-delivery-limit` as a backstop for crash loops, and optionally\n * `x-single-active-consumer`; bound to the topic exchange once per destination;\n * - one retry queue per delay tier: a queue-level `x-message-ttl`, expired\n * messages dead-lettered through the default exchange back to the main queue;\n * - a direct dead-letter exchange and the dead-letter queue, bound with the main\n * queue's name as routing key.\n *\n * Declaring an existing queue with different arguments makes the broker close\n * the channel (`PRECONDITION_FAILED`); see the README for migrating a queue\n * created by an older version or with other options.\n */\nexport async function assertConsumerTopology(\n channel: AmqpChannel,\n topology: ConsumerTopology,\n): Promise<void> {\n await assertExchange(channel, topology.exchange);\n await channel.assertExchange(topology.deadLetterExchange, 'direct', { durable: true });\n await channel.assertQueue(topology.deadLetterQueue, {\n durable: true,\n arguments: { 'x-queue-type': 'quorum' },\n });\n await channel.bindQueue(topology.deadLetterQueue, topology.deadLetterExchange, topology.queue);\n for (const delayMs of topology.retryDelaysMs) {\n await channel.assertQueue(retryQueueName(topology.queue, delayMs), {\n durable: true,\n arguments: {\n 'x-queue-type': 'quorum',\n 'x-message-ttl': delayMs,\n 'x-dead-letter-exchange': '',\n 'x-dead-letter-routing-key': topology.queue,\n 'x-dead-letter-strategy': 'at-least-once',\n 'x-overflow': 'reject-publish',\n },\n });\n }\n await channel.assertQueue(topology.queue, {\n durable: true,\n arguments: {\n 'x-queue-type': 'quorum',\n 'x-delivery-limit': topology.deliveryLimit,\n 'x-dead-letter-exchange': topology.deadLetterExchange,\n 'x-dead-letter-routing-key': topology.queue,\n 'x-dead-letter-strategy': 'at-least-once',\n 'x-overflow': 'reject-publish',\n ...(topology.ordered ? { 'x-single-active-consumer': true } : {}),\n },\n });\n for (const destination of topology.destinations) {\n await channel.bindQueue(topology.queue, topology.exchange, destination);\n }\n}\n","import { UnserializablePayloadError } from './errors.js';\n\n/**\n * Throws {@link UnserializablePayloadError} unless `JSON.stringify` represents\n * `payload` faithfully. Only `null`, strings, booleans, finite numbers, arrays\n * and plain objects built from those are accepted. Everything `JSON.stringify`\n * would silently drop (`undefined`, functions, symbols, symbol keys, array holes),\n * convert (NaN and Infinity to `null`, Dates to strings, Maps and Sets to `{}`,\n * class instances to their own properties) or reject late (BigInt, cycles) is\n * refused up front, naming the offending path.\n */\nexport function assertJsonPayload(payload: unknown, eventId: string): void {\n visit(payload, '$', new Set(), eventId);\n}\n\nfunction visit(value: unknown, path: string, ancestors: Set<object>, eventId: string): void {\n switch (typeof value) {\n case 'string':\n case 'boolean':\n return;\n case 'number':\n if (!Number.isFinite(value)) {\n throw refuse(eventId, path, `is ${value}, which JSON turns into null`);\n }\n return;\n case 'object':\n if (value !== null) {\n visitObject(value, path, ancestors, eventId);\n }\n return;\n default:\n throw refuse(eventId, path, `is ${typeof value}, which JSON cannot represent`);\n }\n}\n\nfunction visitObject(value: object, path: string, ancestors: Set<object>, eventId: string): void {\n if (ancestors.has(value)) {\n throw refuse(eventId, path, 'is a circular reference');\n }\n ancestors.add(value);\n if (Array.isArray(value)) {\n for (let index = 0; index < value.length; index += 1) {\n if (!(index in value)) {\n throw refuse(eventId, `${path}[${index}]`, 'is an array hole, which JSON turns into null');\n }\n visit(value[index], `${path}[${index}]`, ancestors, eventId);\n }\n } else {\n const prototype = Object.getPrototypeOf(value) as object | null;\n if (prototype !== Object.prototype && prototype !== null) {\n throw refuse(eventId, path, 'is not a plain object (class instance, Date, Map or Set)');\n }\n if (Object.getOwnPropertySymbols(value).length > 0) {\n throw refuse(eventId, path, 'has a symbol key, which JSON drops');\n }\n for (const key of Object.keys(value)) {\n visit((value as Record<string, unknown>)[key], `${path}.${key}`, ancestors, eventId);\n }\n }\n ancestors.delete(value);\n}\n\nfunction refuse(eventId: string, path: string, reason: string): UnserializablePayloadError {\n return new UnserializablePayloadError(\n `Event ${eventId} has a payload JSON cannot represent faithfully: ${path} ${reason}`,\n );\n}\n","import type { EventEnvelope, EventHeaders } from '@relaybus/core';\nimport type { AmqpMessage, AmqpPublishOptions } from './amqp-types.js';\nimport { AmqpLimitExceededError, MalformedMessageError } from './errors.js';\nimport { assertJsonPayload } from './json-payload.js';\n\n/**\n * Wire format: CloudEvents 1.0 in binary content mode, following the CloudEvents\n * AMQP protocol binding adapted to RabbitMQ's AMQP 0-9-1.\n *\n * - Body: the JSON-encoded payload (`contentType` `application/json`).\n * - Headers `cloudEvents:specversion`, `cloudEvents:id`, `cloudEvents:type`,\n * `cloudEvents:source`, `cloudEvents:time` (RFC 3339, millisecond precision),\n * `cloudEvents:datacontenttype`, and when present `cloudEvents:subject` (the\n * key) and the extension attributes `cloudEvents:causationid` and\n * `cloudEvents:correlationid`.\n * - AMQP properties mirror the same values for broker tooling: `messageId`,\n * `type`, `appId` (source), `correlationId`, `timestamp` (seconds), plus\n * `deliveryMode` 2 (persistent).\n * - Event headers travel as `relaybus:<name>` message headers, so they cannot\n * collide with CloudEvents attributes or broker headers such as `x-death`.\n *\n * On receive the `cloudEvents:` headers win; the AMQP properties are the\n * fallback for events produced by other CloudEvents libraries (the AMQP\n * timestamp only when `cloudEvents:time` is absent; a present but malformed\n * time is rejected).\n *\n * AMQP 0-9-1 short strings (message properties, header names, routing keys) are\n * limited to 255 bytes. The event id, a header name or a routing key beyond\n * that is refused with {@link AmqpLimitExceededError}, because the event could\n * never be published. The `type`, `appId` and `correlationId` mirrors are\n * skipped when they do not fit; the `cloudEvents:` headers always carry them.\n */\nconst ATTRIBUTE_PREFIX = 'cloudEvents:';\nconst EVENT_HEADER_PREFIX = 'relaybus:';\nconst SPEC_VERSION = '1.0';\nconst JSON_CONTENT_TYPE = 'application/json';\nconst SHORT_STRING_LIMIT_BYTES = 255;\nconst RFC3339_PATTERN = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$/i;\n\n/** A serialized event, ready for `channel.publish`. */\nexport interface EncodedMessage {\n readonly content: Buffer;\n readonly options: AmqpPublishOptions;\n}\n\n/**\n * Serializes an envelope.\n *\n * @throws {UnserializablePayloadError} the payload is not representable as JSON\n * @throws {AmqpLimitExceededError} the id or a header name exceeds 255 bytes\n */\nexport function encodeEnvelope(envelope: EventEnvelope): EncodedMessage {\n assertJsonPayload(envelope.payload, envelope.id);\n assertShortString('Event id', envelope.id);\n const headers: Record<string, string> = {\n [`${ATTRIBUTE_PREFIX}specversion`]: SPEC_VERSION,\n [`${ATTRIBUTE_PREFIX}id`]: envelope.id,\n [`${ATTRIBUTE_PREFIX}type`]: envelope.type,\n [`${ATTRIBUTE_PREFIX}source`]: envelope.source,\n [`${ATTRIBUTE_PREFIX}time`]: envelope.occurredAt.toISOString(),\n [`${ATTRIBUTE_PREFIX}datacontenttype`]: JSON_CONTENT_TYPE,\n };\n if (envelope.key !== null) {\n headers[`${ATTRIBUTE_PREFIX}subject`] = envelope.key;\n }\n if (envelope.causationId !== null) {\n headers[`${ATTRIBUTE_PREFIX}causationid`] = envelope.causationId;\n }\n if (envelope.correlationId !== null) {\n headers[`${ATTRIBUTE_PREFIX}correlationid`] = envelope.correlationId;\n }\n for (const [name, value] of Object.entries(envelope.headers)) {\n assertShortString(\n `Header name '${EVENT_HEADER_PREFIX}${name}'`,\n `${EVENT_HEADER_PREFIX}${name}`,\n );\n headers[`${EVENT_HEADER_PREFIX}${name}`] = value;\n }\n return {\n content: Buffer.from(JSON.stringify(envelope.payload), 'utf8'),\n options: {\n contentType: JSON_CONTENT_TYPE,\n persistent: true,\n messageId: envelope.id,\n timestamp: Math.floor(envelope.occurredAt.getTime() / 1_000),\n ...mirror('type', envelope.type),\n ...mirror('appId', envelope.source),\n ...(envelope.correlationId === null ? {} : mirror('correlationId', envelope.correlationId)),\n headers,\n },\n };\n}\n\n/**\n * Throws {@link AmqpLimitExceededError} when `value` does not fit an AMQP short\n * string (255 bytes of UTF-8), which amqplib would otherwise reject on every\n * attempt.\n */\nexport function assertShortString(label: string, value: string): void {\n const bytes = Buffer.byteLength(value, 'utf8');\n if (bytes > SHORT_STRING_LIMIT_BYTES) {\n throw new AmqpLimitExceededError(\n `${label} is ${bytes} bytes, above the AMQP limit of ${SHORT_STRING_LIMIT_BYTES} bytes`,\n );\n }\n}\n\nfunction mirror<TName extends 'type' | 'appId' | 'correlationId'>(\n name: TName,\n value: string,\n): { [Name in TName]?: string } {\n return Buffer.byteLength(value, 'utf8') > SHORT_STRING_LIMIT_BYTES\n ? {}\n : ({ [name]: value } as { [Name in TName]?: string });\n}\n\n/** Rebuilds an envelope. Throws {@link MalformedMessageError} when the message is not a relaybus event. */\nexport function decodeEnvelope(message: AmqpMessage): EventEnvelope {\n const { properties } = message;\n const attributes = properties.headers ?? {};\n if (attributes[`${ATTRIBUTE_PREFIX}specversion`] !== SPEC_VERSION) {\n throw new MalformedMessageError(\n `Message is not a CloudEvents ${SPEC_VERSION} event (header ${ATTRIBUTE_PREFIX}specversion)`,\n );\n }\n return {\n id: required('id', text(attributes[`${ATTRIBUTE_PREFIX}id`]) ?? text(properties.messageId)),\n type: required('type', text(attributes[`${ATTRIBUTE_PREFIX}type`]) ?? text(properties.type)),\n source: required(\n 'source',\n text(attributes[`${ATTRIBUTE_PREFIX}source`]) ?? text(properties.appId),\n ),\n key: text(attributes[`${ATTRIBUTE_PREFIX}subject`]) ?? null,\n payload: parsePayload(message.content),\n headers: extractEventHeaders(attributes),\n correlationId:\n text(attributes[`${ATTRIBUTE_PREFIX}correlationid`]) ??\n text(properties.correlationId) ??\n null,\n causationId: text(attributes[`${ATTRIBUTE_PREFIX}causationid`]) ?? null,\n occurredAt: parseTime(attributes[`${ATTRIBUTE_PREFIX}time`], properties.timestamp),\n };\n}\n\nfunction extractEventHeaders(attributes: Readonly<Record<string, unknown>>): EventHeaders {\n const headers: Record<string, string> = {};\n for (const [name, value] of Object.entries(attributes)) {\n if (name.startsWith(EVENT_HEADER_PREFIX) && typeof value === 'string') {\n // defineProperty, because assigning `__proto__` would set the prototype and lose the header.\n Object.defineProperty(headers, name.slice(EVENT_HEADER_PREFIX.length), {\n value,\n enumerable: true,\n writable: true,\n configurable: true,\n });\n }\n }\n return headers;\n}\n\nfunction parsePayload(content: Buffer): unknown {\n try {\n return JSON.parse(content.toString('utf8')) as unknown;\n } catch {\n throw new MalformedMessageError('Message body is not valid JSON');\n }\n}\n\nfunction parseTime(rawTime: unknown, timestampSeconds: unknown): Date {\n if (rawTime === undefined) {\n const fallback =\n typeof timestampSeconds === 'number' ? new Date(timestampSeconds * 1_000) : undefined;\n if (fallback === undefined || Number.isNaN(fallback.getTime())) {\n throw new MalformedMessageError('Message has no valid time (header cloudEvents:time)');\n }\n return fallback;\n }\n const occurredAt =\n typeof rawTime === 'string' && RFC3339_PATTERN.test(rawTime) ? new Date(rawTime) : undefined;\n if (occurredAt === undefined || Number.isNaN(occurredAt.getTime())) {\n throw new MalformedMessageError(\n 'Message time (header cloudEvents:time) is not an RFC 3339 timestamp',\n );\n }\n return occurredAt;\n}\n\nfunction text(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction required(attribute: string, value: string | undefined): string {\n if (value === undefined || value.length === 0) {\n throw new MalformedMessageError(\n `Message has no ${attribute} (header ${ATTRIBUTE_PREFIX}${attribute})`,\n );\n }\n return value;\n}\n","import {\n computeRetryDelay,\n isRetryableError,\n toErrorInfo,\n type EventEnvelope,\n type RelayBusLogger,\n type RetryPolicy,\n type TransportMessageHandler,\n} from '@relaybus/core';\nimport { abortableSleep } from './abortable-sleep.js';\nimport type { AmqpChannel, AmqpMessage, AmqpPublishOptions } from './amqp-types.js';\nimport { RabbitMqUnavailableError } from './errors.js';\nimport {\n DEAD_LETTER_REASON_HEADER,\n FIRST_FAILURE_HEADER,\n REDELIVERIES_HEADER,\n chooseRetryTier,\n copyForRepublish,\n readCounterHeader,\n} from './redelivery.js';\nimport { retryQueueName } from './topology.js';\nimport { decodeEnvelope } from './wire-format.js';\n\n/** Publishes a message and resolves only after the broker confirmed it was routed to a queue. */\nexport type ConfirmedRepublish = (\n exchange: string,\n routingKey: string,\n content: Buffer,\n options: AmqpPublishOptions,\n) => Promise<void>;\n\nexport interface QueueConsumerSettings {\n readonly queue: string;\n readonly prefetch: number;\n readonly handlerRetry: RetryPolicy;\n /** Backoff between delayed redeliveries. */\n readonly redelivery: RetryPolicy;\n /** Delays of the retry queues, ascending. Unused when ordered. */\n readonly retryLadder: readonly number[];\n /** A message failing for longer than this is dead-lettered. */\n readonly redeliveryMaxAgeMs: number;\n /** Retry in place instead of through the retry queues, so order is kept. */\n readonly ordered: boolean;\n readonly deadLetterExchange: string;\n readonly shutdownTimeoutMs: number;\n readonly onMessage: TransportMessageHandler;\n /** The consumer's channel closed or the broker cancelled the consumer. */\n readonly onConsumerLost: (reason: string) => void;\n /** Publishes to another queue on a confirm channel; rejects when the copy is not confirmed. */\n readonly republish: ConfirmedRepublish;\n readonly logger: RelayBusLogger;\n readonly random: () => number;\n}\n\ntype Settlement = 'ack' | 'requeue' | 'dead-letter';\n\n/**\n * Consumes one queue with manual acknowledgements.\n *\n * A message is acknowledged only after the handler resolved. When the handler\n * fails it is first retried on the same delivery with short backoff\n * (`handlerRetry`). If that does not help, a copy goes to the retry queue whose\n * TTL matches the next backoff step, and the original is acknowledged only\n * after the broker confirmed the copy; the copy returns to the main queue when\n * its TTL expires. This waits out a long outage of the handler's dependency.\n *\n * Malformed messages, non-retryable errors and messages that kept failing for\n * `redeliveryMaxAgeMs` go to the dead-letter exchange through a confirmed copy\n * (carrying the reason, without retry state, so a replay starts fresh) and the\n * original is acknowledged afterwards. If a copy cannot be confirmed the\n * original is requeued or rejected without requeue, which makes the broker\n * dead-letter it; it is never acknowledged unprocessed, so nothing is lost.\n *\n * In ordered mode nothing is moved: the failing message is retried in place with\n * the same backoff, holding the queue.\n */\nexport class QueueConsumer {\n readonly #settings: QueueConsumerSettings;\n readonly #inFlight = new Set<Promise<void>>();\n readonly #stopping = new AbortController();\n #channel: AmqpChannel | undefined;\n #consumerTag: string | undefined;\n\n constructor(settings: QueueConsumerSettings) {\n this.#settings = settings;\n }\n\n /** True while a consumer is registered on a live channel. */\n isActive(): boolean {\n return this.#consumerTag !== undefined;\n }\n\n /**\n * Starts consuming on a channel whose topology is already declared.\n *\n * @throws {RabbitMqUnavailableError} the channel closed while it was being set up\n */\n async attach(channel: AmqpChannel): Promise<void> {\n let closedDuringSetup = false;\n channel.on('error', (error: Error) => {\n this.#settings.logger.warn(\n `[QueueConsumer](attach) Channel error | queue=${this.#settings.queue} error=${error.message}`,\n );\n });\n channel.on('close', () => {\n closedDuringSetup = true;\n if (this.#channel === channel) {\n this.#channel = undefined;\n this.#consumerTag = undefined;\n this.#settings.onConsumerLost('consumer channel closed');\n }\n });\n await channel.prefetch(this.#settings.prefetch);\n const { consumerTag } = await channel.consume(\n this.#settings.queue,\n (message) => this.#receive(channel, message),\n { noAck: false },\n );\n if (closedDuringSetup) {\n throw new RabbitMqUnavailableError(\n `[QueueConsumer](attach) Consumer channel closed while the consumer was being set up | queue=${this.#settings.queue}`,\n );\n }\n this.#channel = channel;\n this.#consumerTag = consumerTag;\n }\n\n /** Forgets the channel without closing it, because its connection is gone. */\n detach(): void {\n this.#channel = undefined;\n this.#consumerTag = undefined;\n }\n\n /**\n * Stops taking messages, aborts pending handler backoff (those messages are\n * requeued), waits up to the shutdown timeout for running handlers, then\n * closes the channel. Unacknowledged messages return to the queue.\n */\n async stop(): Promise<void> {\n this.#stopping.abort();\n const channel = this.#channel;\n const consumerTag = this.#consumerTag;\n this.#channel = undefined;\n this.#consumerTag = undefined;\n if (channel !== undefined && consumerTag !== undefined) {\n await channel.cancel(consumerTag).catch((error: unknown) => {\n this.#settings.logger.warn(\n `[QueueConsumer](stop) Could not cancel consumer | queue=${this.#settings.queue} error=${toErrorInfo(error).message}`,\n );\n });\n }\n await this.#awaitInFlight();\n await channel?.close().catch(() => undefined);\n }\n\n async #awaitInFlight(): Promise<void> {\n if (this.#inFlight.size === 0) {\n return;\n }\n const timeout = new AbortController();\n const timedOut = abortableSleep(this.#settings.shutdownTimeoutMs, timeout.signal);\n await Promise.race([Promise.allSettled([...this.#inFlight]), timedOut]);\n timeout.abort();\n }\n\n #receive(channel: AmqpChannel, message: AmqpMessage | null): void {\n if (message === null) {\n this.#consumerTag = undefined;\n this.#settings.onConsumerLost('consumer cancelled by the broker');\n return;\n }\n const task: Promise<void> = this.#process(channel, message).finally(() => {\n this.#inFlight.delete(task);\n });\n this.#inFlight.add(task);\n }\n\n async #process(channel: AmqpChannel, message: AmqpMessage): Promise<void> {\n const { queue, handlerRetry } = this.#settings;\n let envelope: EventEnvelope;\n try {\n envelope = decodeEnvelope(message);\n } catch (error) {\n this.#settings.logger.error(\n `[QueueConsumer](process) Dead-lettering malformed message | queue=${queue} routingKey=${message.fields.routingKey} error=${toErrorInfo(error).message}`,\n );\n await this.#deadLetter(channel, message, 'malformed message');\n return;\n }\n let redeliveries = readCounterHeader(message, REDELIVERIES_HEADER) ?? 0;\n let firstFailureAt = readCounterHeader(message, FIRST_FAILURE_HEADER);\n for (let attempt = 1; ; attempt += 1) {\n try {\n await this.#settings.onMessage(envelope);\n this.#settle(channel, message, 'ack');\n return;\n } catch (error) {\n const failure = `queue=${queue} eventId=${envelope.id} attempt=${attempt} error=${toErrorInfo(error).message}`;\n if (!isRetryableError(handlerRetry, error)) {\n this.#settings.logger.error(\n `[QueueConsumer](process) Dead-lettering message the handler cannot process | ${failure}`,\n );\n await this.#deadLetter(channel, message, 'non-retryable handler error');\n return;\n }\n if (attempt < handlerRetry.attempts) {\n const delayMs = computeRetryDelay(handlerRetry, attempt, this.#settings.random);\n this.#settings.logger.warn(\n `[QueueConsumer](process) Handler failed, retrying | ${failure} delayMs=${delayMs}`,\n );\n if (await this.#interrupted(delayMs)) {\n this.#settle(channel, message, 'requeue');\n return;\n }\n continue;\n }\n redeliveries += 1;\n const now = Date.now();\n firstFailureAt ??= now;\n const delayMs = this.#redeliveryDelay(redeliveries);\n if (now + delayMs - firstFailureAt > this.#settings.redeliveryMaxAgeMs) {\n this.#settings.logger.error(\n `[QueueConsumer](process) Dead-lettering message that kept failing | ${failure} redeliveries=${redeliveries - 1} failingForMs=${now - firstFailureAt} maxAgeMs=${this.#settings.redeliveryMaxAgeMs}`,\n );\n await this.#deadLetter(channel, message, 'redelivery window exhausted');\n return;\n }\n this.#settings.logger.warn(\n `[QueueConsumer](process) Handler attempts spent, retrying later | ${failure} redeliveries=${redeliveries} delayMs=${delayMs}`,\n );\n if (!this.#settings.ordered) {\n await this.#redeliverLater(channel, message, delayMs, redeliveries, firstFailureAt);\n return;\n }\n if (await this.#interrupted(delayMs)) {\n this.#settle(channel, message, 'requeue');\n return;\n }\n }\n }\n }\n\n /** The backoff before the next delayed redelivery: a retry queue's TTL, or an exact wait when ordered. */\n #redeliveryDelay(redeliveries: number): number {\n const { redelivery, retryLadder, ordered, random } = this.#settings;\n const delayMs = computeRetryDelay(redelivery, redeliveries, random);\n return ordered ? delayMs : chooseRetryTier(retryLadder, delayMs, random);\n }\n\n /** Sleeps; true when the consumer is stopping, so the caller must give the message back. */\n async #interrupted(delayMs: number): Promise<boolean> {\n await abortableSleep(delayMs, this.#stopping.signal);\n return this.#stopping.signal.aborted;\n }\n\n /**\n * Parks a copy in the retry queue of `delayMs` and acknowledges the original\n * only once the broker confirmed the copy. When the copy cannot be confirmed\n * the original is requeued after the same delay, so it is neither lost nor\n * hot-looped.\n */\n async #redeliverLater(\n channel: AmqpChannel,\n message: AmqpMessage,\n delayMs: number,\n redeliveries: number,\n firstFailureAt: number,\n ): Promise<void> {\n const { content, options } = copyForRepublish(message, {\n [REDELIVERIES_HEADER]: String(redeliveries),\n [FIRST_FAILURE_HEADER]: String(firstFailureAt),\n });\n try {\n await this.#settings.republish(\n '',\n retryQueueName(this.#settings.queue, delayMs),\n content,\n options,\n );\n } catch (error) {\n this.#settings.logger.warn(\n `[QueueConsumer](redeliverLater) Could not park the message in the retry queue, requeueing it | queue=${this.#settings.queue} delayMs=${delayMs} error=${toErrorInfo(error).message}`,\n );\n await this.#interrupted(delayMs);\n this.#settle(channel, message, 'requeue');\n return;\n }\n this.#settle(channel, message, 'ack');\n }\n\n /**\n * Moves the message to the dead-letter queue through a confirmed copy that\n * carries the reason and no retry state. If the copy cannot be confirmed the\n * message is rejected without requeue, which makes the broker dead-letter it\n * (at-least-once), so it still ends up in the dead-letter queue.\n */\n async #deadLetter(channel: AmqpChannel, message: AmqpMessage, reason: string): Promise<void> {\n const { content, options } = copyForRepublish(message, {\n [DEAD_LETTER_REASON_HEADER]: reason,\n });\n try {\n await this.#settings.republish(\n this.#settings.deadLetterExchange,\n this.#settings.queue,\n content,\n options,\n );\n } catch (error) {\n this.#settings.logger.warn(\n `[QueueConsumer](deadLetter) Could not publish to the dead-letter exchange, leaving it to the broker | queue=${this.#settings.queue} error=${toErrorInfo(error).message}`,\n );\n this.#settle(channel, message, 'dead-letter');\n return;\n }\n this.#settle(channel, message, 'ack');\n }\n\n #settle(channel: AmqpChannel, message: AmqpMessage, settlement: Settlement): void {\n try {\n if (settlement === 'ack') {\n channel.ack(message);\n } else {\n channel.nack(message, false, settlement === 'requeue');\n }\n } catch (error) {\n // The channel is gone; the broker redelivers the message and the inbox drops the duplicate.\n this.#settings.logger.warn(\n `[QueueConsumer](settle) Could not ${settlement} message, the broker will redeliver it | queue=${this.#settings.queue} error=${toErrorInfo(error).message}`,\n );\n }\n }\n}\n","/** Runs async tasks one after another, in submission order, even when one fails. */\nexport class SerialQueue {\n #tail: Promise<unknown> = Promise.resolve();\n\n run<TResult>(task: () => Promise<TResult>): Promise<TResult> {\n const result = this.#tail.then(task);\n this.#tail = result.catch(() => undefined);\n return result;\n }\n}\n","import {\n ConfigurationError,\n toErrorInfo,\n type EventEnvelope,\n type Transport,\n type TransportMessageHandler,\n} from '@relaybus/core';\nimport type {\n AmqpConfirmChannel,\n AmqpConnection,\n AmqpMessage,\n AmqpPublishOptions,\n} from './amqp-types.js';\nimport { ConnectionSupervisor } from './connection-supervisor.js';\nimport {\n RabbitMqPublishRejectedError,\n RabbitMqUnavailableError,\n UnroutableMessageError,\n} from './errors.js';\nimport {\n resolveQueueName,\n resolveSettings,\n type RabbitMqTransportOptions,\n type ResolvedTransportSettings,\n} from './options.js';\nimport { QueueConsumer } from './queue-consumer.js';\nimport { SerialQueue } from './serial-queue.js';\nimport { assertConsumerTopology, assertExchange, type ConsumerTopology } from './topology.js';\nimport { assertShortString, encodeEnvelope } from './wire-format.js';\n\n/** Publisher channel plus the broker returns not yet matched with their confirm. */\ninterface Publisher {\n readonly channel: AmqpConfirmChannel;\n readonly unroutable: Map<string, number>;\n /** Set when the channel closed, also while the transport was still being set up. */\n closed: boolean;\n}\n\ninterface LiveConnection {\n readonly connection: AmqpConnection;\n readonly publisher: Publisher;\n}\n\ninterface Subscription {\n readonly topology: ConsumerTopology;\n readonly consumer: QueueConsumer;\n}\n\n/** amqplib reports a negative acknowledgement with this exact message. */\nconst NACK_MESSAGE = 'message nacked';\n\n/**\n * RabbitMQ {@link Transport} built on amqplib.\n *\n * Publishing: each event goes to a durable topic exchange as a persistent,\n * mandatory message with the destination as routing key. `publish` resolves\n * only after the broker confirmed it was persisted and routed to a queue, and\n * rejects when the transport is disconnected, the broker nacks, the message is\n * unroutable or no confirm arrives in time. It never drops a message silently,\n * so the outbox retries the delivery.\n *\n * Subscribing: one durable quorum queue per consumer group, bound to the\n * destinations (routing-key patterns such as `orders.*`). A message is\n * acknowledged only after the handler resolved. A failing handler is retried\n * on the same delivery, then through retry queues with growing delays (see\n * `redelivery`), and finally dead-lettered after the retry window; poison\n * messages are dead-lettered at once. Nothing is lost on the way.\n *\n * Reconnection: after a connection or channel loss the transport reconnects\n * with capped, jittered backoff and restores channels, topology and the\n * consumer. Events published meanwhile are rejected, and therefore retried by\n * the outbox, rather than buffered in memory.\n */\nexport class RabbitMqTransport implements Transport {\n readonly name: string;\n readonly #settings: ResolvedTransportSettings;\n readonly #supervisor: ConnectionSupervisor;\n /** Serializes topology work so a subscription never races a reconnect. */\n readonly #topologyWork = new SerialQueue();\n #live: LiveConnection | undefined;\n #subscription: Subscription | undefined;\n #closed = false;\n\n constructor(options: RabbitMqTransportOptions) {\n this.#settings = resolveSettings(options);\n this.name = this.#settings.name;\n this.#supervisor = new ConnectionSupervisor({\n connect: this.#settings.connect,\n reconnect: this.#settings.reconnect,\n onConnected: (connection) => this.#establishChannels(connection),\n onDisconnected: () => this.#forgetConnection(),\n logger: this.#settings.logger,\n random: this.#settings.random,\n });\n }\n\n /**\n * True while the connection is open and publishing and consuming are set up.\n * Use it for readiness probes.\n */\n isConnected(): boolean {\n return this.#supervisor.isConnected();\n }\n\n /**\n * True when the transport can publish and, once subscribed, is consuming: the\n * connection is up, its channels are open and the consumer is registered. False while reconnecting and after a cancelled consumer.\n */\n isReady(): boolean {\n return (\n this.#supervisor.isConnected() &&\n this.#live !== undefined &&\n (this.#subscription === undefined || this.#subscription.consumer.isActive())\n );\n }\n\n /** Connects to the broker. Rejects when it is unreachable unless `failOnConnectError` is false. */\n async connect(): Promise<void> {\n await this.#supervisor.start(this.#settings.failOnConnectError);\n }\n\n /**\n * Publishes to the exchange with `destination` as routing key and resolves\n * after the broker confirmed the message.\n *\n * @throws {UnserializablePayloadError} the payload is not representable as JSON (never retried)\n * @throws {AmqpLimitExceededError} the event id, a header name or `destination` exceeds 255 bytes (never retried)\n * @throws {RabbitMqUnavailableError} not connected, channel lost, or confirm timed out\n * @throws {RabbitMqPublishRejectedError} the broker nacked the message\n * @throws {UnroutableMessageError} no queue is bound to `destination` (unless `allowUnroutable`)\n */\n async publish(envelope: EventEnvelope, destination: string): Promise<void> {\n assertShortString('Destination (routing key)', destination);\n const { content, options } = encodeEnvelope(envelope);\n await this.#publishConfirmed(\n this.#settings.exchange,\n destination,\n content,\n options,\n !this.#settings.allowUnroutable,\n );\n }\n\n async #publishConfirmed(\n exchange: string,\n routingKey: string,\n content: Buffer,\n options: AmqpPublishOptions,\n mandatory: boolean,\n ): Promise<void> {\n const publisher = this.#live?.publisher;\n const eventId = options.messageId ?? 'unknown';\n if (publisher === undefined) {\n throw new RabbitMqUnavailableError(\n `[RabbitMqTransport](publish) Not connected to the broker | transport=${this.name} destination=${routingKey}`,\n );\n }\n const returnKey = unroutableKey(options.messageId, routingKey);\n await new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(\n new RabbitMqUnavailableError(\n `[RabbitMqTransport](publish) No broker confirm within ${this.#settings.publishTimeoutMs}ms | transport=${this.name} eventId=${eventId} destination=${routingKey}`,\n ),\n );\n }, this.#settings.publishTimeoutMs);\n const onConfirm = (error: Error | null | undefined): void => {\n clearTimeout(timer);\n const returned = takeUnroutable(publisher.unroutable, returnKey);\n if (error) {\n reject(this.#toPublishError(error, eventId, routingKey));\n } else if (returned) {\n reject(\n new UnroutableMessageError(\n `[RabbitMqTransport](publish) No queue is bound to the routing key | transport=${this.name} eventId=${eventId} destination=${routingKey}`,\n ),\n );\n } else {\n resolve();\n }\n };\n try {\n publisher.channel.publish(\n exchange,\n routingKey,\n content,\n { ...options, mandatory },\n onConfirm,\n );\n } catch (error) {\n clearTimeout(timer);\n reject(this.#toPublishError(error, eventId, routingKey));\n }\n });\n }\n\n /**\n * Binds one durable quorum queue to `destinations` and delivers its messages\n * to `onMessage`. Call it once per transport; give each subscription its own\n * transport instance, with its own `name` and `consumerGroup`.\n */\n async subscribe(\n destinations: readonly string[],\n onMessage: TransportMessageHandler,\n ): Promise<void> {\n if (this.#subscription !== undefined) {\n throw new ConfigurationError(\n `Transport '${this.name}' already has a subscription; create another transport for another consumer group`,\n );\n }\n if (destinations.length === 0) {\n throw new ConfigurationError(`Transport '${this.name}' needs at least one destination`);\n }\n const queue = resolveQueueName(this.#settings);\n const subscription: Subscription = {\n topology: {\n exchange: this.#settings.exchange,\n queue,\n deadLetterExchange: this.#settings.deadLetterExchange,\n deadLetterQueue: this.#settings.deadLetterQueue ?? `${queue}.dead`,\n deliveryLimit: this.#settings.deliveryLimit,\n ordered: this.#settings.ordered,\n retryDelaysMs: this.#settings.retryLadder,\n destinations,\n },\n consumer: new QueueConsumer({\n queue,\n prefetch: this.#settings.prefetch,\n handlerRetry: this.#settings.handlerRetry,\n redelivery: this.#settings.redelivery,\n retryLadder: this.#settings.retryLadder,\n redeliveryMaxAgeMs: this.#settings.redeliveryMaxAgeMs,\n ordered: this.#settings.ordered,\n deadLetterExchange: this.#settings.deadLetterExchange,\n republish: (exchange, routingKey, content, options) =>\n this.#publishConfirmed(exchange, routingKey, content, options, true),\n shutdownTimeoutMs: this.#settings.shutdownTimeoutMs,\n onMessage,\n onConsumerLost: (reason) => this.#supervisor.recover(reason),\n logger: this.#settings.logger,\n random: this.#settings.random,\n }),\n };\n await this.#topologyWork.run(async () => {\n this.#subscription = subscription;\n if (this.#live !== undefined) {\n await this.#startConsuming(this.#live.connection, subscription);\n }\n });\n }\n\n /**\n * Stops consuming, waits up to `shutdownTimeout` for running handlers\n * (messages still being retried go back to the queue), then closes the\n * channels and the connection.\n */\n async close(): Promise<void> {\n if (this.#closed) {\n return;\n }\n this.#closed = true;\n await this.#supervisor.close(() =>\n this.#topologyWork.run(async () => {\n const live = this.#live;\n this.#live = undefined;\n await this.#subscription?.consumer.stop();\n await live?.publisher.channel.close().catch(() => undefined);\n }),\n );\n }\n\n async #establishChannels(connection: AmqpConnection): Promise<void> {\n await this.#topologyWork.run(async () => {\n const channel = await connection.createConfirmChannel();\n const publisher: Publisher = { channel, unroutable: new Map(), closed: false };\n channel.on('error', (error: Error) => {\n this.#settings.logger.warn(\n `[RabbitMqTransport](establishChannels) Publisher channel error | transport=${this.name} error=${error.message}`,\n );\n });\n channel.on('close', () => {\n publisher.closed = true;\n if (this.#live?.publisher === publisher) {\n this.#supervisor.recover('publisher channel closed');\n }\n });\n channel.on('return', (message: AmqpMessage) => {\n recordUnroutable(\n publisher.unroutable,\n unroutableKey(message.properties.messageId, message.fields.routingKey),\n );\n });\n await assertExchange(channel, this.#settings.exchange);\n if (this.#subscription !== undefined) {\n await this.#startConsuming(connection, this.#subscription);\n }\n if (publisher.closed) {\n // The close came before `live` was set, so nothing reacted to it.\n throw new RabbitMqUnavailableError(\n `[RabbitMqTransport](establishChannels) Publisher channel closed while the transport was being set up | transport=${this.name}`,\n );\n }\n this.#live = { connection, publisher };\n });\n }\n\n async #startConsuming(connection: AmqpConnection, subscription: Subscription): Promise<void> {\n const channel = await connection.createChannel();\n await assertConsumerTopology(channel, subscription.topology);\n await subscription.consumer.attach(channel);\n }\n\n #forgetConnection(): void {\n this.#live = undefined;\n this.#subscription?.consumer.detach();\n }\n\n #toPublishError(error: unknown, eventId: string, destination: string): Error {\n const { message } = toErrorInfo(error);\n const detail = `transport=${this.name} eventId=${eventId} destination=${destination} error=${message}`;\n return message === NACK_MESSAGE\n ? new RabbitMqPublishRejectedError(\n `[RabbitMqTransport](publish) Broker nacked the message | ${detail}`,\n { cause: error },\n )\n : new RabbitMqUnavailableError(`[RabbitMqTransport](publish) Publish failed | ${detail}`, {\n cause: error,\n });\n }\n}\n\nfunction unroutableKey(messageId: unknown, routingKey: string): string {\n return `${String(messageId)}\\n${routingKey}`;\n}\n\nfunction recordUnroutable(unroutable: Map<string, number>, key: string): void {\n unroutable.set(key, (unroutable.get(key) ?? 0) + 1);\n}\n\nfunction takeUnroutable(unroutable: Map<string, number>, key: string): boolean {\n const count = unroutable.get(key);\n if (count === undefined) {\n return false;\n }\n if (count === 1) {\n unroutable.delete(key);\n } else {\n unroutable.set(key, count - 1);\n }\n return true;\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { NonRetryableError, RelayBusError, RetryPolicyOptions, Duration, RelayBusLogger, Transport, EventEnvelope, TransportMessageHandler } from '@relaybus/core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The slice of amqplib this package relies on. Declaring it here keeps the
|
|
6
|
+
* public types independent of the amqplib version (peer range `>=0.10`) and
|
|
7
|
+
* lets tests substitute fakes. Real amqplib connections and channels satisfy it.
|
|
8
|
+
*/
|
|
9
|
+
/** Message properties as delivered by the broker. */
|
|
10
|
+
interface AmqpMessageProperties {
|
|
11
|
+
readonly messageId?: unknown;
|
|
12
|
+
readonly type?: unknown;
|
|
13
|
+
readonly appId?: unknown;
|
|
14
|
+
readonly correlationId?: unknown;
|
|
15
|
+
readonly timestamp?: unknown;
|
|
16
|
+
readonly contentType?: unknown;
|
|
17
|
+
readonly headers?: Readonly<Record<string, unknown>> | undefined;
|
|
18
|
+
}
|
|
19
|
+
/** A message delivered to a consumer or returned by the broker. */
|
|
20
|
+
interface AmqpMessage {
|
|
21
|
+
readonly content: Buffer;
|
|
22
|
+
readonly fields: {
|
|
23
|
+
readonly routingKey: string;
|
|
24
|
+
};
|
|
25
|
+
readonly properties: AmqpMessageProperties;
|
|
26
|
+
}
|
|
27
|
+
/** Properties set on a published message. */
|
|
28
|
+
interface AmqpPublishOptions {
|
|
29
|
+
readonly contentType: string;
|
|
30
|
+
readonly persistent: boolean;
|
|
31
|
+
readonly mandatory?: boolean;
|
|
32
|
+
readonly messageId?: string;
|
|
33
|
+
readonly type?: string;
|
|
34
|
+
readonly appId?: string;
|
|
35
|
+
readonly timestamp?: number;
|
|
36
|
+
readonly correlationId?: string;
|
|
37
|
+
readonly headers: Readonly<Record<string, unknown>>;
|
|
38
|
+
}
|
|
39
|
+
/** Channel used for consuming. */
|
|
40
|
+
interface AmqpChannel extends EventEmitter {
|
|
41
|
+
assertExchange(exchange: string, type: string, options?: {
|
|
42
|
+
readonly durable?: boolean;
|
|
43
|
+
}): Promise<unknown>;
|
|
44
|
+
assertQueue(queue: string, options?: {
|
|
45
|
+
readonly durable?: boolean;
|
|
46
|
+
readonly arguments?: Record<string, unknown>;
|
|
47
|
+
}): Promise<unknown>;
|
|
48
|
+
bindQueue(queue: string, source: string, pattern: string): Promise<unknown>;
|
|
49
|
+
prefetch(count: number): Promise<unknown>;
|
|
50
|
+
consume(queue: string, onMessage: (message: AmqpMessage | null) => void, options?: {
|
|
51
|
+
readonly noAck?: boolean;
|
|
52
|
+
}): Promise<{
|
|
53
|
+
readonly consumerTag: string;
|
|
54
|
+
}>;
|
|
55
|
+
cancel(consumerTag: string): Promise<unknown>;
|
|
56
|
+
ack(message: AmqpMessage): void;
|
|
57
|
+
nack(message: AmqpMessage, allUpTo?: boolean, requeue?: boolean): void;
|
|
58
|
+
close(): Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
/** Channel with publisher confirms. */
|
|
61
|
+
interface AmqpConfirmChannel extends AmqpChannel {
|
|
62
|
+
publish(exchange: string, routingKey: string, content: Buffer, options: AmqpPublishOptions, callback: (error: Error | null | undefined) => void): boolean;
|
|
63
|
+
}
|
|
64
|
+
/** A broker connection. Emits `close` and `error`. */
|
|
65
|
+
interface AmqpConnection extends EventEmitter {
|
|
66
|
+
createChannel(): Promise<AmqpChannel>;
|
|
67
|
+
createConfirmChannel(): Promise<AmqpConfirmChannel>;
|
|
68
|
+
close(): Promise<void>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The broker cannot take or confirm a message right now: the transport is not
|
|
73
|
+
* connected, was closed, lost its channel, or the confirm did not arrive in time.
|
|
74
|
+
* Always retryable; the outbox keeps the delivery and tries again.
|
|
75
|
+
*/
|
|
76
|
+
declare class RabbitMqUnavailableError extends RelayBusError {
|
|
77
|
+
}
|
|
78
|
+
/** The broker negatively acknowledged a published message. Retryable. */
|
|
79
|
+
declare class RabbitMqPublishRejectedError extends RelayBusError {
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The broker accepted the message but no queue is bound to its routing key, so
|
|
83
|
+
* it would have been discarded. Retryable: it succeeds once a consumer binds.
|
|
84
|
+
*/
|
|
85
|
+
declare class UnroutableMessageError extends RelayBusError {
|
|
86
|
+
}
|
|
87
|
+
/** A received message is not a valid relaybus CloudEvent. It is dead-lettered. */
|
|
88
|
+
declare class MalformedMessageError extends RelayBusError {
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The payload of an event cannot be represented as JSON without losing or
|
|
92
|
+
* changing data (`undefined`, functions, symbols, BigInt, NaN, Infinity, Dates,
|
|
93
|
+
* Maps, class instances, cycles). Never retried: the payload will not change.
|
|
94
|
+
*/
|
|
95
|
+
declare class UnserializablePayloadError extends NonRetryableError {
|
|
96
|
+
name: string;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* A value exceeds a protocol limit of AMQP 0-9-1, for example an event id or a
|
|
100
|
+
* routing key longer than the 255 bytes of a short string. Never retried.
|
|
101
|
+
*/
|
|
102
|
+
declare class AmqpLimitExceededError extends NonRetryableError {
|
|
103
|
+
name: string;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Connection settings accepted by `amqplib.connect`, given as an object instead of a URL. */
|
|
107
|
+
interface BrokerConnectionSettings {
|
|
108
|
+
readonly protocol?: string;
|
|
109
|
+
readonly hostname?: string;
|
|
110
|
+
readonly port?: number;
|
|
111
|
+
readonly username?: string;
|
|
112
|
+
readonly password?: string;
|
|
113
|
+
readonly vhost?: string;
|
|
114
|
+
/** Seconds. See "Operational notes" in the README for the heartbeat defaults of each amqplib version. */
|
|
115
|
+
readonly heartbeat?: number;
|
|
116
|
+
}
|
|
117
|
+
/** Backoff between reconnect attempts. Attempts are unlimited. */
|
|
118
|
+
type ReconnectOptions = Pick<RetryPolicyOptions, 'initialDelay' | 'factor' | 'maxDelay' | 'jitter'>;
|
|
119
|
+
/**
|
|
120
|
+
* Delayed redelivery of messages whose handler keeps failing. Each failed
|
|
121
|
+
* delivery goes to a retry queue and returns to the main queue after a growing
|
|
122
|
+
* delay, so an outage of the handler's dependency is waited out instead of
|
|
123
|
+
* burning through delivery attempts.
|
|
124
|
+
*/
|
|
125
|
+
type RedeliveryOptions = Pick<RetryPolicyOptions, 'initialDelay' | 'factor' | 'maxDelay' | 'jitter'> & {
|
|
126
|
+
/**
|
|
127
|
+
* How long a message may keep failing, counted from its first delayed
|
|
128
|
+
* redelivery, before it is dead-lettered. Default `'1h'`.
|
|
129
|
+
*/
|
|
130
|
+
readonly maxAge?: Duration;
|
|
131
|
+
};
|
|
132
|
+
interface RabbitMqTransportOptions {
|
|
133
|
+
/** Name referenced by routes and subscriptions. Default `'rabbitmq'`. */
|
|
134
|
+
readonly name?: string;
|
|
135
|
+
/**
|
|
136
|
+
* Broker location, for example `amqp://user:pass@host:5672/vhost?heartbeat=30`.
|
|
137
|
+
* Give exactly one of `url` and `connect`.
|
|
138
|
+
*/
|
|
139
|
+
readonly url?: string | BrokerConnectionSettings;
|
|
140
|
+
/**
|
|
141
|
+
* Opens one connection. Called again after every connection loss. Use it for
|
|
142
|
+
* TLS options, custom credentials or an alternative amqplib instance.
|
|
143
|
+
*/
|
|
144
|
+
readonly connect?: () => Promise<AmqpConnection>;
|
|
145
|
+
/** Topic exchange events are published to. Durable, created when missing. Default `'relaybus'`. */
|
|
146
|
+
readonly exchange?: string;
|
|
147
|
+
/**
|
|
148
|
+
* Unacknowledged messages the consumer holds, which is also its concurrency.
|
|
149
|
+
* Default 50, or 1 when `ordered`.
|
|
150
|
+
*/
|
|
151
|
+
readonly prefetch?: number;
|
|
152
|
+
/** Prefix of derived queue names. Default `'relaybus'`. */
|
|
153
|
+
readonly queuePrefix?: string;
|
|
154
|
+
/**
|
|
155
|
+
* Consumer group: services sharing it share one queue and split the messages,
|
|
156
|
+
* services with different groups each receive every message. The queue is
|
|
157
|
+
* `<queuePrefix>.<consumerGroup>`. Required when subscribing, unless `queue` is set.
|
|
158
|
+
*/
|
|
159
|
+
readonly consumerGroup?: string;
|
|
160
|
+
/** Explicit queue name. Overrides `queuePrefix` and `consumerGroup`. */
|
|
161
|
+
readonly queue?: string;
|
|
162
|
+
/** Exchange poison messages are dead-lettered to. Default `'<exchange>.dead'`. */
|
|
163
|
+
readonly deadLetterExchange?: string;
|
|
164
|
+
/** Queue that keeps dead-lettered messages for inspection. Default `'<queue>.dead'`. */
|
|
165
|
+
readonly deadLetterQueue?: string;
|
|
166
|
+
/**
|
|
167
|
+
* Quorum queue `x-delivery-limit`: deliveries after which the broker itself
|
|
168
|
+
* dead-letters a message. Failing handlers do not consume it (they use
|
|
169
|
+
* `redelivery`); it only stops a message that crashes the consumer or its
|
|
170
|
+
* channel again and again. Default 10.
|
|
171
|
+
*/
|
|
172
|
+
readonly deliveryLimit?: number;
|
|
173
|
+
/**
|
|
174
|
+
* Handler attempts on the same delivery, with backoff, before the message is
|
|
175
|
+
* scheduled for delayed redelivery. Absorbs short blips without a broker round
|
|
176
|
+
* trip. Default: 3 attempts, 200 ms initial delay, factor 2, 5 s cap, equal jitter.
|
|
177
|
+
*/
|
|
178
|
+
readonly handlerRetry?: RetryPolicyOptions;
|
|
179
|
+
/**
|
|
180
|
+
* Delayed redelivery after `handlerRetry` is spent. Default: 2 s initial
|
|
181
|
+
* delay, factor 2, 5 min cap, equal jitter, dead-lettered after 1 h of
|
|
182
|
+
* failing (about 18 redeliveries). Delays are quantized to the retry queues,
|
|
183
|
+
* one per step of the exponential ladder (9 queues with the defaults).
|
|
184
|
+
* Ignored when `ordered`, where the same delays are waited in place.
|
|
185
|
+
*/
|
|
186
|
+
readonly redelivery?: RedeliveryOptions;
|
|
187
|
+
/**
|
|
188
|
+
* Consume the queue strictly in order: a single active consumer across all
|
|
189
|
+
* replicas, one message at a time, a failing message is retried in place
|
|
190
|
+
* (blocking the queue) instead of being delayed. Needed when
|
|
191
|
+
* `EventEnvelope.key` order matters; costs throughput, because one handler
|
|
192
|
+
* runs at a time. Default false: handlers run concurrently and a delayed
|
|
193
|
+
* redelivery overtakes later messages, so order is not preserved.
|
|
194
|
+
*/
|
|
195
|
+
readonly ordered?: boolean;
|
|
196
|
+
/** Reconnect backoff, or `false` to never reconnect. Default: 500 ms initial, factor 2, 30 s cap, equal jitter. */
|
|
197
|
+
readonly reconnect?: ReconnectOptions | false;
|
|
198
|
+
/**
|
|
199
|
+
* When true (default) `connect()` rejects if the broker is unreachable, which
|
|
200
|
+
* fails startup. When false it resolves and keeps trying in the background.
|
|
201
|
+
*/
|
|
202
|
+
readonly failOnConnectError?: boolean;
|
|
203
|
+
/**
|
|
204
|
+
* When false (default) a message that no queue is bound to makes `publish`
|
|
205
|
+
* reject. When true it resolves and the broker silently discards the message.
|
|
206
|
+
*/
|
|
207
|
+
readonly allowUnroutable?: boolean;
|
|
208
|
+
/** How long `publish` waits for the broker confirm. Default `'30s'`. */
|
|
209
|
+
readonly publishTimeout?: Duration;
|
|
210
|
+
/** How long `close` waits for running handlers. Default `'30s'`. */
|
|
211
|
+
readonly shutdownTimeout?: Duration;
|
|
212
|
+
/** Default: `console`. */
|
|
213
|
+
readonly logger?: RelayBusLogger;
|
|
214
|
+
/** Random source for jitter. Default `Math.random`. Intended for tests. */
|
|
215
|
+
readonly random?: () => number;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* RabbitMQ {@link Transport} built on amqplib.
|
|
220
|
+
*
|
|
221
|
+
* Publishing: each event goes to a durable topic exchange as a persistent,
|
|
222
|
+
* mandatory message with the destination as routing key. `publish` resolves
|
|
223
|
+
* only after the broker confirmed it was persisted and routed to a queue, and
|
|
224
|
+
* rejects when the transport is disconnected, the broker nacks, the message is
|
|
225
|
+
* unroutable or no confirm arrives in time. It never drops a message silently,
|
|
226
|
+
* so the outbox retries the delivery.
|
|
227
|
+
*
|
|
228
|
+
* Subscribing: one durable quorum queue per consumer group, bound to the
|
|
229
|
+
* destinations (routing-key patterns such as `orders.*`). A message is
|
|
230
|
+
* acknowledged only after the handler resolved. A failing handler is retried
|
|
231
|
+
* on the same delivery, then through retry queues with growing delays (see
|
|
232
|
+
* `redelivery`), and finally dead-lettered after the retry window; poison
|
|
233
|
+
* messages are dead-lettered at once. Nothing is lost on the way.
|
|
234
|
+
*
|
|
235
|
+
* Reconnection: after a connection or channel loss the transport reconnects
|
|
236
|
+
* with capped, jittered backoff and restores channels, topology and the
|
|
237
|
+
* consumer. Events published meanwhile are rejected, and therefore retried by
|
|
238
|
+
* the outbox, rather than buffered in memory.
|
|
239
|
+
*/
|
|
240
|
+
declare class RabbitMqTransport implements Transport {
|
|
241
|
+
#private;
|
|
242
|
+
readonly name: string;
|
|
243
|
+
constructor(options: RabbitMqTransportOptions);
|
|
244
|
+
/**
|
|
245
|
+
* True while the connection is open and publishing and consuming are set up.
|
|
246
|
+
* Use it for readiness probes.
|
|
247
|
+
*/
|
|
248
|
+
isConnected(): boolean;
|
|
249
|
+
/**
|
|
250
|
+
* True when the transport can publish and, once subscribed, is consuming: the
|
|
251
|
+
* connection is up, its channels are open and the consumer is registered. False while reconnecting and after a cancelled consumer.
|
|
252
|
+
*/
|
|
253
|
+
isReady(): boolean;
|
|
254
|
+
/** Connects to the broker. Rejects when it is unreachable unless `failOnConnectError` is false. */
|
|
255
|
+
connect(): Promise<void>;
|
|
256
|
+
/**
|
|
257
|
+
* Publishes to the exchange with `destination` as routing key and resolves
|
|
258
|
+
* after the broker confirmed the message.
|
|
259
|
+
*
|
|
260
|
+
* @throws {UnserializablePayloadError} the payload is not representable as JSON (never retried)
|
|
261
|
+
* @throws {AmqpLimitExceededError} the event id, a header name or `destination` exceeds 255 bytes (never retried)
|
|
262
|
+
* @throws {RabbitMqUnavailableError} not connected, channel lost, or confirm timed out
|
|
263
|
+
* @throws {RabbitMqPublishRejectedError} the broker nacked the message
|
|
264
|
+
* @throws {UnroutableMessageError} no queue is bound to `destination` (unless `allowUnroutable`)
|
|
265
|
+
*/
|
|
266
|
+
publish(envelope: EventEnvelope, destination: string): Promise<void>;
|
|
267
|
+
/**
|
|
268
|
+
* Binds one durable quorum queue to `destinations` and delivers its messages
|
|
269
|
+
* to `onMessage`. Call it once per transport; give each subscription its own
|
|
270
|
+
* transport instance, with its own `name` and `consumerGroup`.
|
|
271
|
+
*/
|
|
272
|
+
subscribe(destinations: readonly string[], onMessage: TransportMessageHandler): Promise<void>;
|
|
273
|
+
/**
|
|
274
|
+
* Stops consuming, waits up to `shutdownTimeout` for running handlers
|
|
275
|
+
* (messages still being retried go back to the queue), then closes the
|
|
276
|
+
* channels and the connection.
|
|
277
|
+
*/
|
|
278
|
+
close(): Promise<void>;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export { type AmqpChannel, type AmqpConfirmChannel, type AmqpConnection, AmqpLimitExceededError, type AmqpMessage, type AmqpMessageProperties, type AmqpPublishOptions, type BrokerConnectionSettings, MalformedMessageError, RabbitMqPublishRejectedError, RabbitMqTransport, type RabbitMqTransportOptions, RabbitMqUnavailableError, type ReconnectOptions, type RedeliveryOptions, UnroutableMessageError, UnserializablePayloadError };
|