10

I've been looking at MassTransit for a couple of weeks now and I'm curious about the possibilities. However, I don't seem to be able to get the concepts quite right.

Expected behaviour I wanted to publish message to "direct" exchange with routing key which is bind to two different queue for performing other activities.

When I attempted the same logic using MassTransit for better scalability. I've found MassTransit creates own exchange based on queue name with fanout type.

Classic code to publish message by exchange and routing key

using (var connection = factory.CreateConnection())
        {
            using (var channel = connection.CreateModel())
            {
                channel.ExchangeDeclare(exchange, "direct");

                var body = Encoding.UTF8.GetBytes(message);

                channel.BasicPublish(exchange, routingKey, null, body);
                Console.WriteLine(" [x] Sent {0}", message);
            }
        }

Is there a way to configure direct or topic exchange with routingkey in MassTransit?

Travis
  • 10,444
  • 2
  • 28
  • 48
Syed
  • 417
  • 1
  • 6
  • 13

3 Answers3

7

Following code does the same work, but with one extra fanout exchange:

TestMessage (direct exchange) -> TestMessage_Queue(fanout exchange) -> TestMessage_Queue (queue)

var bus = Bus.Factory.CreateUsingRabbitMq(cfg =>
{
    var host = cfg.Host(new Uri("rabbitmq://localhost"), h =>
    {
        h.Username("guest");
        h.Password("guest");
    });
    cfg.Send<TestMessage>(x => { x.UseRoutingKeyFormatter(context => "routingKey"); });
    cfg.Message<TestMessage>(x => x.SetEntityName("TestMessage"));
    cfg.Publish<TestMessage>(x => { x.ExchangeType = ExchangeType.Direct; });
    cfg.ReceiveEndpoint(host, "TestMessage_Queue", e =>
    {
        e.BindMessageExchanges = false;
        e.Consumer<UpdateCustomerConsumer>();
        e.Bind("TestMessage", x =>
        {
            x.ExchangeType = ExchangeType.Direct;
            x.RoutingKey = "routingKey";
        });
    });
});

bus.Start();
Jan Muncinsky
  • 4,282
  • 4
  • 22
  • 40
4

This is not a supported scenario with MassTransit. MassTransit will always create a fanout queue. If you managed your topology yourself, you can use IEndpoint.Send to directly send the message to the exchange you created. In this case you give up much what MT provides though.

I'm also not sure what "better scalability" means in this case. Fanout exchanges perform better than direct exchanges (in most cases) since there's no routing logic that needs to be processed.

Maybe if you clarified your performance concerns on the MassTransit mailing list we could help you a bit more there.

Travis
  • 10,444
  • 2
  • 28
  • 48
  • Thanks for your comments, My process would need multiple publishers to post messages in parallel so thought of "direct" or "topic" exchanges but they are not supported in MassTransit. Do you have any suggestion on best way to handle this or do you prefer to use multiple queue for this process. Also, It would be helpful if you direct me towards the architecture of MassTransit. – Syed May 10 '15 at 13:17
  • I'm not really sure what you're trying to do. Publishing messages in parallel doesn't really make sense to me. With MT 3.0 you can do async publishes. Everything is more or less in parallel with messaging though. If one thread is publishing so can another. Same with consuming. – Travis May 11 '15 at 19:57
  • Basically, forget about the topology in RMQ, and just define you message contracts with types (preferably interfaces) and let MT bind it all together for you. – Travis May 11 '15 at 19:58
3

MassTransit handles publish and subscribe without using topic exchanges, instead creating exchanges for the message types being published, and binding those exchanges to the consumer queues.

The routing key approach is less efficient with RabbitMQ, which prefers to use the exchange fabric for message routing simplicity (no hash tables to maintain).

Instead of dealing with exchanges and routing keys, just define your command and/or event types, and the send or publish those messages and let the consumers do their work.

Chris Patterson
  • 28,659
  • 3
  • 47
  • 59
  • 3
    Creating extra types, while very clean, can be tedious. A tempting approach is that your bus doesn't even know what exact types are exchanged because you wrap everything in a generic "wrapper-like" type (possibly with losing static typing as there is just the single wrapper type). However, a distadvantage of a single wrapper-like type is that technically, there's a fan from a single exchange to all subscribers and thus all subscribers retrieve all messages, filtering has to be done internally, in handlers. – Wiktor Zychla Feb 20 '19 at 12:32
  • This is where routing key approach becomes handy. By having an explicit key with every wrapped message and routing keys mapped to queues you can control subscriptions in an exact way. Fortunately, this seems to work in MT, as mentioned in the other answer by @jan-mucinsky. I am not advocating for this model, I am only saying this is technically possible and there's a rationale behind it. – Wiktor Zychla Feb 20 '19 at 12:34
  • @WiktorZychla were you able to figure out how to implement this? – Aranha Nov 08 '21 at 10:25
  • @Aranha: yep, [dropped a blog entry note on that](https://www.wiktorzychla.com/2019/03/) – Wiktor Zychla Nov 08 '21 at 10:59