Skip to content

The search box in the website knows all the secrets—try it!

For any queries, join our Discord Channel to reach us faster.

JasperFx Logo

JasperFx provides formal support for Wolverine and other JasperFx libraries. Please check our Support Plans for more details.

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:

cs
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();

snippet source | anchor

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:

cs
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();

snippet source | anchor

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:

cs
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();

snippet source | anchor

Released under the MIT License.