简体   繁体   中英

MassTransit: Queue is not created for topic exchange

I want to send stock prices data to rabbitmq using topic exchange. The idea is I have a topic exchange with the following routing key:

<message-type>.<ticker>

I was able to do it with native RabbitMQ cient, but I cannot figure out how to do it with help of MassTransit.

// setup topologies
rabbitCfg.Send<ComMessage>(x =>
{
   x.UseRoutingKeyFormatter(context => 
        $"quote.{context.Message.Ticker}");
});

rabbitCfg.Message<ComMessage>(x => x.SetEntityName("Quotes"));
rabbitCfg.Publish<ComMessage>(x =>
{
   x.ExchangeType = ExchangeType.Topic;
});


// setup reciever
rabbitCfg.ReceiveEndpoint(host, "MSFT", e =>
{
   e.Bind("Quotes", c =>
      {
         c.RoutingKey = "quote.MSFT";
         c.ExchangeType = ExchangeType.Topic;
      });

   e.Consumer<PriceConsumer>();
});

Send message:

await _bus.Publish(new ComMessage
{
   Ticker = "MSFT",
   Price = "10"
});

But, it doesn't work. The queue is not created, but exchange recieves messages:

在此处输入图片说明

Where is a problem?

I think you forgot one important line. And for reference, I've included the source of a working unit test using topic exchanges.

In your receive endpoint, you need to disable automatic exchange binding.

cfg.ReceiveEndpoint(host, "MSFT", x =>
{
    x.BindMessageExchanges = false;
    ...
}

A working example is shown below:

using System;
using System.Threading.Tasks;
using GreenPipes.Util;
using NUnit.Framework;
using RabbitMQ.Client;
using RoutingKeyTopic;


namespace RoutingKeyTopic
{
    public class Message
    {
        public Message(decimal price, string symbol)
        {
            Price = price;
            Symbol = symbol;
        }

        public string Symbol { get; set; }

        public decimal Price { get; set; }
    }
}


[TestFixture]
public class Using_a_routing_key_and_topic_exchange :
    RabbitMqTestFixture
{
    [Test]
    public async Task Should_support_routing_by_key_and_exchange_name()
    {
        var fooHandle = await Subscribe("MSFT");
        try
        {
            var barHandle = await Subscribe("UBER");
            try
            {
                await Bus.Publish(new Message(100.0m, "MSFT"));
                await Bus.Publish(new Message(3.50m, "UBER"));

                await Consumer.Microsoft;
                await Consumer.Uber;
            }
            finally
            {
                await barHandle.StopAsync(TestCancellationToken);
            }
        }
        finally
        {
            await fooHandle.StopAsync(TestCancellationToken);
        }
    }

    async Task<HostReceiveEndpointHandle> Subscribe(string key)
    {
        var queueName = $"Stock-{key}";
        var handle = Host.ConnectReceiveEndpoint(queueName, x =>
        {
            x.BindMessageExchanges = false;
            x.Consumer<Consumer>();

            x.Bind<Message>(e =>
            {
                e.RoutingKey = GetRoutingKey(key);
                e.ExchangeType = ExchangeType.Topic;
            });
        });

        await handle.Ready;

        return handle;
    }

    protected override void ConfigureRabbitMqBusHost(IRabbitMqBusFactoryConfigurator configurator, IRabbitMqHost host)
    {
        base.ConfigureRabbitMqBusHost(configurator, host);

        configurator.Message<Message>(x => x.SetEntityName(ExchangeName));
        configurator.Publish<Message>(x => x.ExchangeType = ExchangeType.Topic);

        configurator.Send<Message>(x => x.UseRoutingKeyFormatter(context => GetRoutingKey(context.Message.Symbol)));
    }

    string ExchangeName { get; } = "Quotes";

    string GetRoutingKey(string routingKey)
    {
        return $"quote.{routingKey}";
    }


    class Consumer :
        IConsumer<Message>
    {
        static readonly TaskCompletionSource<Message> _microsoft = new TaskCompletionSource<Message>();
        static readonly TaskCompletionSource<Message> _uber = new TaskCompletionSource<Message>();
        public static Task<Message> Microsoft => _microsoft.Task;
        public static Task<Message> Uber => _uber.Task;

        public Task Consume(ConsumeContext<Message> context)
        {
            Console.WriteLine($"Received {context.Message.Symbol} for {context.RoutingKey()}");

            if (context.Message.Symbol == "MSFT")
                _microsoft.TrySetResult(context.Message);

            if (context.Message.Symbol == "UBER")
                _uber.TrySetResult(context.Message);

            return TaskUtil.Completed;
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM