Reputation: 2063
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:
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:
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:
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
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.
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