Skip to content

Using Rabbit MQ

TIP

Wolverine uses the Rabbit MQ .NET Client to connect to Rabbit MQ.

Installing

All the code samples in this section are from the Ping/Pong with Rabbit MQ sample project.

To use RabbitMQ as a transport with Wolverine, first install the Wolverine.RabbitMQ library via nuget to your project. Behind the scenes, this package uses the RabbitMQ C# Client to both send and receive messages from RabbitMQ.

cs
return await Host.CreateDefaultBuilder(args)
    .UseWolverine(opts =>
    {
        // Listen for messages coming into the pongs queue
        opts
            .ListenToRabbitQueue("pongs")

            // This won't be necessary by the time Wolverine goes 2.0
            // but for now, I've got to help Wolverine out a little bit
            .UseForReplies();

        // Publish messages to the pings queue
        opts.PublishMessage<PingMessage>().ToRabbitExchange("pings");

        // Configure Rabbit MQ connection properties programmatically
        // against a ConnectionFactory
        opts.UseRabbitMq(rabbit =>
            {
                // Using a local installation of Rabbit MQ
                // via a running Docker image
                rabbit.HostName = "localhost";
            })
            // Directs Wolverine to build any declared queues, exchanges, or
            // bindings with the Rabbit MQ broker as part of bootstrapping time
            .AutoProvision();

        // Or you can use this functionality to set up *all* known
        // Wolverine (or Marten) related resources on application startup
        opts.Services.AddResourceSetupOnStartup();

        // This will send ping messages on a continuous
        // loop
        opts.Services.AddHostedService<PingerService>();
    }).RunOaktonCommands(args);

snippet source | anchor

See the Rabbit MQ .NET Client documentation for more information about configuring the ConnectionFactory to connect to Rabbit MQ.

Managing Rabbit MQ Connections

In its default setup, the Rabbit MQ transport in Wolverine will open two connections, one for listening and another for sending messages. All Rabbit MQ endpoints will share these two connections. If you need to conserve Rabbit MQ connections and have a process that is only sending or only receiving messages through Rabbit MQ, you can opt to turn off one or the other connections that might not be used at runtime.

To only listen to Rabbit MQ messages, but never send them:

cs
using var host = await Host.CreateDefaultBuilder()
    .UseWolverine(opts =>
    {
        // *A* way to configure Rabbit MQ using their Uri schema
        // documented here: https://www.rabbitmq.com/uri-spec.html
        opts.UseRabbitMq(new Uri("amqp://localhost"))

            // Turn on listener connection only in case if you only need to listen for messages
            // The sender connection won't be activated in this case
            .UseListenerConnectionOnly();

        // Set up a listener for a queue, but also
        // fine-tune the queue characteristics if Wolverine
        // will be governing the queue setup
        opts.ListenToRabbitQueue("incoming2", q =>
        {
            q.PurgeOnStartup = true;
            q.TimeToLive(5.Minutes());
        });
    }).StartAsync();

snippet source | anchor

To only send Rabbit MQ messages, but never receive them:

cs
using var host = await Host.CreateDefaultBuilder()
    .UseWolverine(opts =>
    {
        // *A* way to configure Rabbit MQ using their Uri schema
        // documented here: https://www.rabbitmq.com/uri-spec.html
        opts.UseRabbitMq(new Uri("amqp://localhost"))

            // Turn on sender connection only in case if you only need to send messages
            // The listener connection won't be created in this case
            .UseSenderConnectionOnly();

        // Set up a listener for a queue, but also
        // fine-tune the queue characteristics if Wolverine
        // will be governing the queue setup
        opts.ListenToRabbitQueue("incoming2", q =>
        {
            q.PurgeOnStartup = true;
            q.TimeToLive(5.Minutes());
        });
    }).StartAsync();

snippet source | anchor

Enable Rabbit MQ for Wolverine Control Queues

If you are using Wolverine in a cluster of running nodes -- and it's more likely that you are than not if you have any kind of non trivial load -- Wolverine needs to communicate between its running nodes for various reasons if you are using any kind of message persistence. Normally that communication is done through little, specialized database queueing (crude polling), but there's an option to use more efficient Rabbit MQ queues for that inter-node communication with a non-durable Rabbit MQ queue for each node with this option:

cs
using var host = await Host.CreateDefaultBuilder()
    .UseWolverine(opts =>
    {
        // *A* way to configure Rabbit MQ using their Uri schema
        // documented here: https://www.rabbitmq.com/uri-spec.html
        opts.UseRabbitMq(new Uri("amqp://localhost"))

            // Use Rabbit MQ for inter-node communication
            .EnableWolverineControlQueues();
    }).StartAsync();

snippet source | anchor

Disable Rabbit MQ Reply Queues

By default, Wolverine creates an in memory queue in the Rabbit MQ broker for each individual node that is used by Wolverine for request/reply invocations (IMessageBus.InvokeAsync<T>() when used remotely). Great, but if your process does not have permissions with your Rabbit MQ broker to create queues, you may encounter errors. Not to worry, you can disable that Wolverine system queue creation with:

cs
using var host = await Host.CreateDefaultBuilder()
    .UseWolverine(opts =>
    {
        // *A* way to configure Rabbit MQ using their Uri schema
        // documented here: https://www.rabbitmq.com/uri-spec.html
        opts.UseRabbitMq(new Uri("amqp://localhost"))
            
            // Stop Wolverine from trying to create a reply queue
            // for this node if your process does not have permission to
            // do so against your Rabbit MQ broker
            .DisableSystemRequestReplyQueueDeclaration();

        

        // Set up a listener for a queue, but also
        // fine-tune the queue characteristics if Wolverine
        // will be governing the queue setup
        opts.ListenToRabbitQueue("incoming2", q =>
        {
            q.PurgeOnStartup = true;
            q.TimeToLive(5.Minutes());
        });
    }).StartAsync();

snippet source | anchor

Of course, doing so means that you will not be able to do request/reply through Rabbit MQ with your Wolverine application.

Released under the MIT License.