Queues and topology
Configure physical queues, bindings, retention and topology ownership separately from message handlers.
A handler macro identifies the physical queue, version and content contract it handles. TOML selects that queue’s exchange, binding and runtime policy. [rabbitmq.consumer] is the connection profile; [[rabbitmq.topology.queues]] defines topology without credentials.
Define a complete queue#
Use this entry with the connection profile from your first application. Replace an existing entry with the same name; do not add a second orders.created entry.
[[rabbitmq.topology.queues]]
name = "orders.created"
exchange_name = "orders"
routing_key = "orders.created"
exchange_kind = "direct"
queue_type = "classic"
topology_ownership = "framework_managed"
concurrency = 2
prefetch_count = 10
[rabbitmq.topology.queues.retention]
main_max_messages = 100000
main_max_bytes = 1073741824
retry_bucket_max_messages = 10000
retry_bucket_max_bytes = 268435456
dead_letter_max_messages = 10000
dead_letter_max_bytes = 268435456All six retention fields are required and must lie in 1..=i64::MAX. The canonical definition requires them even when retries are disabled. The main queue, each retry bucket and the DLQ are separate physical resources; these values do not form one shared capacity pool.
Supported queue options#
| Option | Contract |
|---|---|
exchange_kind |
Only direct |
queue_type |
classic or quorum |
durable |
Defaults to true; required for quorum |
exclusive |
True is rejected; bootstrap and runtime use separate pooled connections |
auto_delete |
Defaults to false; quorum rejects true |
single_active_consumer |
Defaults to false; broker option for one active consumer |
max_priority |
1..16 for classic; rejected for quorum |
Queue, exchange and routing identities must contain 1–200 trimmed bytes without control characters. Derived retry/DLQ names are validated too; a 200-byte main name may leave no room for derived names. Secret/file references are not allowed in these identities.
Who creates the resources?#
framework_managed is the default: Lily declares exchanges, queues and bindings from the accepted immutable plan. Startup may fail if an existing queue has different declaration arguments. Lily does not delete the old queue or migrate its messages; manage the change in your deployment plan.
# Fields in the existing queue entry, before its retention table.
topology_ownership = "external"
dead_letter_exchange = "operations.dlx"
dead_letter_routing_key = "orders.rejected"External mode checks exchange/queue existence passively and does not create resources. Supply the DLX and dead-letter routing key explicitly; the operator provisions every required resource, including retry buckets and the DLQ. Bindings remain operator-unverified: existence checks do not prove bindings or every retention argument are correct.
Validate the plan before connecting#
use lilyrs::config::{RabbitMqTopologyConfig, RabbitMqTopologyPlan, RabbitMqTopologyPlanError};
fn validate_topology(config: &RabbitMqTopologyConfig)
-> Result<RabbitMqTopologyPlan, RabbitMqTopologyPlanError>
{
RabbitMqTopologyPlan::compile(config)
}This helper requires the facade’s config feature alongside consumer. Plan validation neither connects to the broker nor tests permissions. A publisher-only process does not initialize topology automatically; use the explicit bootstrap described in the publisher guide.
Sources for this page v0.1.0
This guide is based on the reviewed framework commit.