Tarta
Tarta

Reputation: 2063

MassTransit under the hood when adding a consumer

I am trying to understand what happens when using MassTransit in such a way not to totally rely on this abstraction-layer-library but to really know and understand what's being created under the hood and the reason behind.

In my application I register consumers in the following way:

container.AddMassTransit(x =>
{
    x.AddBus(context => Bus.Factory.CreateUsingRabbitMq(cfg =>
    {
        var host = cfg.Host(configurationProvider.RabbitHostName);

        x.AddConsumer<FactAddedHandler>();
        x.AddConsumer<FactAddedOrderHandler>();
        x.AddConsumer<FactCategoryHandler>();

        cfg.ConfigureEndpoints(container);
    }));

});

Follow me on this, so far we have therefore this scenario:

enter image description here

When I check out which queues are being created through

rabbitmqctl list_queues name messages consumers

I see:

FactAddedHandler     0       1
FactAddedOrderHandler        0       1
FactCategoryHandler  0       1

which makes me believe indeed that there is a queue per specific consumer. So we have this scenario:

enter image description here

Let's see how these Handlers are defined:

internal class FactAddedHandler : IConsumer<FactAddedIntegrationEvent>
{
    //
}


internal class FactAddedOrderHandler : IConsumer<FactAddedIntegrationEvent>
{
    //
}


internal class FactCategoryHandler : IConsumer<FactCategoryIntegrationEvent>
{
    //
}

So, the first 2 handlers (FactAddedHandler and FactAddedOrderHandler) subscribe to the same event (FactAddedIntegrationEvent), while the other (FactCategoryHandler **) subscribes to another event (**FactCategoryIntegrationEvent).

I would expect therefore that there is "at least" a fanout exchange on top of the first 2 queues that broadcasts the FactAddedIntegrationEvent. So let's check out the exchanges through:

rabbitmqctl list_exchanges name type

and the result is:

FactCategoryHandler     fanout
FactAddedOrderHandler      fanout
FactAddedHandler   fanout

IntegrationEvents:FactAddedIntegrationEvent  fanout
IntegrationEvents:FactCategoryIntegrationEvent    fanout

So.. what I would expect is that the IntegrationEvents:FactAddedIntegrationEvent is the fanout exchange that broadcasts the FactAddedIntegrationEvent.

I also believe that masstransit creates by default the other exchange IntegrationEvents:FactCategoryIntegrationEvent in such a way that it is easy to add other consumers to the same event, even though in my case there is only one.

Therefore we end up in this scenario which still makes sense:

enter image description here

What I do NOT understand and would like an explanation about is the reason for the creation of the other 3 remaining exchanges. What is their role? Why are they there? Thanks in advance!

Upvotes: 1

Views: 697

Answers (1)

Chris Patterson
Chris Patterson

Reputation: 33278

For a receive endpoint, MassTransit creates both a queue and a matching exchange with the same name. The queue is bound to the matching exchange.

The message types consumed by consumers on the receive endpoint are used to declare exchanges (as you've shown above) and the matching exchange is bound to those message type exchanges. All of these exchanges are fanout exchanges.

The resulting topology routes all message types through the matching exchange, which then routes to the queue.

This is explained with an example in the documentation.

RabbitMQ Publish Topology

Why the matching exchange? Two answers.

First, the simple answer, it allows messages to be sent to the exchange with a routing key. Sending to a queue with RabbitMQ requires an empty exchange with the queue name as the routing key.

Second, it allows additional queues to be bound to the matching exchange for troubleshooting purposes. This includes setting up a wiretap to keep a copy of all messages sent to the endpoint (either directly, or via a published message type exchange).

Upvotes: 4

Related Questions