Dead Letter Queues
INFO
The end result is the same regardless, but Wolverine bypasses this functionality to move messages to the dead letter queue in Buffered
or Durable
queue endpoints.
By default, Wolverine's Rabbit MQ transport supports the native dead letter exchange functionality in Rabbit MQ itself. If running completely with default behavior, Wolverine will:
- Declare a queue named
wolverine-dead-letter-queue
as the system dead letter queue for the entire application -- but don't worry, that can be overridden queue by queue - Add the
x-dead-letter-exchange
argument to each non-system queue created by Wolverine in Rabbit MQ
Great, but someone will inevitably want to alter the dead letter queue functionality to use differently named queues like so:
using var host = await Host.CreateDefaultBuilder()
.UseWolverine(opts =>
{
// Use a different default deal letter queue name
opts.UseRabbitMq()
.CustomizeDeadLetterQueueing(new DeadLetterQueue("error-queue"))
// or conventionally
.ConfigureListeners(l => { l.DeadLetterQueueing(new DeadLetterQueue($"{l.QueueName}-errors")); });
// Use a different dead letter queue for this specific queue
opts.ListenToRabbitQueue("incoming")
.DeadLetterQueueing(new DeadLetterQueue("incoming-errors"));
}).StartAsync();
WARNING
You will need this if you are interoperating against NServiceBus!
But wait there's more! Other messaging tools or previous usages of Rabbit MQ in your environment may have already declared the Rabbit MQ queues without the x-dead-letter-exchange
argument, meaning that Wolverine will not be able to declare queues for you, or might do so in a way that interferes with other messaging tools. To avoid all that hassle, you can opt out of native Rabbit MQ dead letter queues with the InteropFriendly
option:
using var host = await Host.CreateDefaultBuilder()
.UseWolverine(opts =>
{
// Use a different default deal letter queue name
opts.UseRabbitMq()
.CustomizeDeadLetterQueueing(
new DeadLetterQueue("error-queue", DeadLetterQueueMode.InteropFriendly))
// or conventionally
.ConfigureListeners(l =>
{
l.DeadLetterQueueing(new DeadLetterQueue($"{l.QueueName}-errors",
DeadLetterQueueMode.InteropFriendly));
});
// Use a different dead letter queue for this specific queue
opts.ListenToRabbitQueue("incoming")
.DeadLetterQueueing(new DeadLetterQueue("incoming-errors", DeadLetterQueueMode.InteropFriendly));
}).StartAsync();
And lastly, if you don't particularly want to have any Rabbit MQ dead letter queues and you quite like the database backed dead letter queues you get with Wolverine's message durability, you can use the WolverineStorage
option:
using var host = await Host.CreateDefaultBuilder()
.UseWolverine(opts =>
{
// Disable dead letter queueing by default
opts.UseRabbitMq()
.DisableDeadLetterQueueing()
// or conventionally
.ConfigureListeners(l =>
{
// Really does the same thing as the first usage
l.DisableDeadLetterQueueing();
});
// Disable the dead letter queue for this specific queue
opts.ListenToRabbitQueue("incoming").DisableDeadLetterQueueing();
}).StartAsync();