pub struct RabbitMqDelivery { /* private fields */ }Expand description
One RabbitMQ message, decoded into an Envelope.
Exactly one of ack, retry,
defer or dead_letter must be
called; the trait consumes the delivery so the compiler enforces “at most
once”, and an un-acked delivery is redelivered by the broker when the
consumer channel closes.
retry, defer and
dead_letter publish before they ack, and
propagate the publish error without acking, so a failure leaves the original
message unacknowledged for the broker to redeliver rather than dropping the
job. Because publishes are mandatory, a missing q.dead counts as a
failure. A hold queue cannot be missing: retry and defer declare it
themselves, immediately before publishing, but that declaration can be
refused, and retry says what happens then.
When
declare_dead_letter_queues
is false this backend does not own q.dead, so
dead_letter rejects the message (requeue = false)
instead of publishing to it, and logs why.
Trait Implementations§
Source§impl Debug for RabbitMqDelivery
impl Debug for RabbitMqDelivery
Source§impl Delivery for RabbitMqDelivery
impl Delivery for RabbitMqDelivery
Source§fn retry<'async_trait>(
self: Box<Self>,
next: Envelope,
delay: Duration,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
fn retry<'async_trait>(
self: Box<Self>,
next: Envelope,
delay: Duration,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
Publish first, ack second.
next is written into the hold queue for delay (declared on the spot,
mandatory, waited on for a publisher confirm) and only once the broker
has taken responsibility for it is the original acked. If the publish
fails the ? returns before the ack, so the original stays
unacknowledged and the broker redelivers it, so the job is retried
rather than silently dropped. The reverse order would lose a job on any
broker hiccup between the two.
The delay is rounded up to
RabbitMqOptions::retry_granularity,
and next returns to q at the priority it carries, 0 after
Envelope::next_attempt, so it joins the back of the queue.
Three things count as that failure, and all three leave the original unacked (the worker counts a settle failure and the broker redelivers the job when the consumer channel closes):
- the hold queue exists with different arguments, so the declaration is
refused with
PRECONDITION_FAILED. The declaration runs on its own channel, so concurrent publishes are untouched; next.queuewas never declared through this backend, so the hold queue’s durability and dead-letter target are unknown (Error::UnknownQueue);delayis longer thanMAX_DEFERRAL_MS(~24.8 days), which is refused rather than shortened, because a hold never releases a job early.
Source§fn defer<'async_trait>(
self: Box<Self>,
next: Envelope,
delay: Duration,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
fn defer<'async_trait>(
self: Box<Self>,
next: Envelope,
delay: Duration,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
Publish first, ack second, the same rule and the same failure modes as
retry.
The delay is rounded up to
RabbitMqOptions::deferred_granularity
instead, and next carries its queue’s top priority, so it returns
ahead of the backlog.
A caveat on “ahead of the backlog”: a consumer with prefetch N is
already holding up to N messages of that backlog, and the returning
deferral cannot overtake those. It is first among what is still on the
queue.