Message Redelivery Configuration
Some errors take a while to resolve, say a remote service is down or a SQL server has crashed. In these situations, it’s best to dust off and nuke the site from orbit — at a much later time, obviously. Redelivery is a form of retry (some refer to it as second-level retry) where the message is removed from the queue and then redelivered to the queue at a future time.
To use delayed redelivery, ensure the transport is properly configured. When using UseDelayedRedelivery on RabbitMQ, the delayed-exchange plug-in is required.
ActiveMQ (non-Artemis) requires the scheduler to be enabled via the XML configuration. For RabbitMQ environments where the plug-in isn’t available,
see Queue-Based Delayed Redelivery below.
services.AddMassTransit(x =>{ x.AddConsumer<SubmitOrderConsumer>();
x.AddConfigureEndpointsCallback((context,name,cfg) => { cfg.UseDelayedRedelivery(r => r.Intervals(TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(30))); cfg.UseMessageRetry(r => r.Immediate(5)); });
x.UsingRabbitMq((context, cfg) => { cfg.ConfigureEndpoints(context); });});Now, if the initial 5 immediate retries fail (the database is really, really down), the message will retry an additional three times after 5, 15, and 30 minutes. This could mean a total of 15 retry attempts (on top of the initial 4 attempts prior to the retry/redelivery filters taking control).
RabbitMQ delayed redelivery
Section titled “RabbitMQ delayed redelivery”Not every RabbitMQ deployment allows plugins: managed instances, locked-down brokers, corporate policies, you name it.
MassTransit has a new queue-based delayed redelivery feature that achieves the same result as the delayed-exchange plug-in but uses plain RabbitMQ features ( message TTL + dead-letter exchanges), no plugins needed.
services.AddMassTransit(x =>{ x.AddConsumer<SubmitOrderConsumer>();
x.AddConfigureEndpointsCallback((context, name, cfg) => { cfg.UseQueueBasedDelayedRedelivery(r => r.Intervals(TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(30))); cfg.UseMessageRetry(r => r.Immediate(5)); });
x.UsingRabbitMq((context, cfg) => { cfg.ConfigureEndpoints(context); });});This is a drop-in replacement for UseDelayedRedelivery. The retry policy API is identical, only the method name changes.
How it works
Section titled “How it works”When the bus starts, MassTransit automatically creates the following infrastructure on the broker:
- A
mt-delay-returndirect exchange that routes expired messages back to the original queue - Per-interval
mt-delay-{ms}exchange + queue pairs, each configured withx-message-ttlset to the delay interval andx-dead-letter-exchangepointing tomt-delay-return
When a message is scheduled for redelivery, it is published to the exchange matching the desired delay. The message sits in the corresponding TTL queue until it
expires, at which point RabbitMQ dead-letters it through mt-delay-return back to the original queue for another attempt.
Routing key preservation
Section titled “Routing key preservation”When queue-based delayed redelivery is necessary, the routing key is used to deliver the message back to its original queue. If the message has an existing
routing key, the original routing key is saved in an MT-Original-RoutingKey header before the message is moved to a delay queue. When the message returns to
the original queue, the routing key is restored transparently. Consumers see the correct RabbitMQ-RoutingKey value as usual.
Choosing an implementation
Section titled “Choosing an implementation”UseDelayedRedelivery | UseQueueBasedDelayedRedelivery | |
|---|---|---|
| RabbitMQ plugins supported | Yes (delayed-exchange) | Optional |
| Native transport support | Any | RabbitMQ only |