Rabbit-Mq被拒绝后不会路由到死信队列

时间:2018-02-02 13:38:00

标签: c# rabbitmq

我正在玩Rabbit-Mq,我正在尝试实现一个“死信”队列,一个失败消息的队列。我一直在阅读兔子文档:https://www.rabbitmq.com/dlx.html

并提出了这个例子:

internal class Program
{
    private const string WorkerExchange = "work.exchange";
    private const string RetryExchange = "retry.exchange";
    public const string WorkerQueue = "work.queue";
    private const string RetryQueue = "retry.queue";

    static void Main(string[] args)
    {
        var factory = new ConnectionFactory { HostName = "localhost" };

        using (var connection = factory.CreateConnection())
        {
            using (var channel = connection.CreateModel())
            {
                channel.ExchangeDeclare(WorkerExchange, "direct");
                channel.QueueDeclare
                (
                    WorkerQueue, true, false, false,
                    new Dictionary<string, object>
                    {
                        {"x-dead-letter-exchange", RetryExchange},

                        // I have tried with and without this next key
                        {"x-dead-letter-routing-key", RetryQueue}
                    }
                );
                channel.QueueBind(WorkerQueue, WorkerExchange, string.Empty, null);

                channel.ExchangeDeclare(RetryExchange, "direct");
                channel.QueueDeclare
                (
                    RetryQueue, true, false, false,
                    new Dictionary<string, object> {
                        { "x-dead-letter-exchange", WorkerExchange },
                        { "x-message-ttl", 30000 },
                    }
                );
                channel.QueueBind(RetryQueue, RetryExchange, string.Empty, null);

                var consumer = new EventingBasicConsumer(channel);
                consumer.Received += (model, ea) =>
                {
                    var body = ea.Body;
                    var message = Encoding.UTF8.GetString(body);
                    Console.WriteLine(" [x] Received {0}", message);

                    Thread.Sleep(1000);
                    Console.WriteLine("Rejected message");

                    // also tried  channel.BasicNack(ea.DeliveryTag, false, false);
                    channel.BasicReject(ea.DeliveryTag, false);
                };

                channel.BasicConsume(WorkerQueue, false, consumer);

                Console.WriteLine(" Press [enter] to exit.");
                Console.ReadLine();
            }
        }
    }
}

发布到工作队列时的队列映像: rabbit-mq worker queue stats

重试队列的图片: rabbit-mq retry stats

我觉得我好像错过了一些小细节,但似乎无法找到它们是什么。

提前致谢

3 个答案:

答案 0 :(得分:4)

您应该将死信交换定义为fanout

我们去:channel.ExchangeDeclare(RetryExchange, "fanout");

  

如果您的死信交换设置为DIRECT,您必须指定一个   死信路由键。如果您只想要所有NACKed消息   进入一个死信桶,以便以后调查(就像我一样)   你的死信交换应该设置为FANOUT。

     

Look at this for more info

答案 1 :(得分:2)

事实证明,如果死信交换是direct交换,则队列参数需要x-dead-letter-routing-key。上面(在问题中)我在字典中使用这个键来尝试路由我的消息,但我没有做的是添加一个路由到我的绑定,这里是一个有效的代码的更新版本:

internal class Program
{
    private const string WorkerExchange = "work.exchange";
    private const string RetryExchange = "retry.exchange";
    public const string WorkerQueue = "work.queue";
    private const string RetryQueue = "retry.queue";

    static void Main(string[] args)
    {
        var factory = new ConnectionFactory { HostName = "localhost" };

        using (var connection = factory.CreateConnection())
        {
            using (var channel = connection.CreateModel())
            {
                channel.ExchangeDeclare(WorkerExchange, "direct");
                channel.QueueDeclare
                (
                    WorkerQueue, true, false, false,
                    new Dictionary<string, object>
                    {
                        {"x-dead-letter-exchange", RetryExchange},
                        {"x-dead-letter-routing-key", RetryQueue}
                    }
                );
                channel.QueueBind(WorkerQueue, WorkerExchange, WorkerQueue, null);

                channel.ExchangeDeclare(RetryExchange, "direct");
                channel.QueueDeclare
                (
                    RetryQueue, true, false, false,
                    new Dictionary<string, object>
                    {
                        {"x-dead-letter-exchange", WorkerExchange},
                        {"x-dead-letter-routing-key", WorkerQueue},
                        {"x-message-ttl", 30000},
                    }
                );
                channel.QueueBind(RetryQueue, RetryExchange, RetryQueue, null);

                var consumer = new EventingBasicConsumer(channel);
                consumer.Received += (model, ea) =>
                {
                    var body = ea.Body;
                    var message = Encoding.UTF8.GetString(body);
                    Console.WriteLine(" [x] Received {0}", message);

                    Thread.Sleep(1000);
                    Console.WriteLine("Rejected message");
                    channel.BasicNack(ea.DeliveryTag, false, false);
                };

                channel.BasicConsume(WorkerQueue, false, consumer);

                Console.WriteLine(" Press [enter] to exit.");
                Console.ReadLine();
            }
        }
    }

不同之处在于对channel.QueueBind(WorkerQueue, WorkerExchange, WorkerQueue, null);的调用现在提供的路由键与queuename相同,所以当消息&#34; dead-letters&#34;它通过此密钥路由到交易所

答案 2 :(得分:0)

要使其正常工作,最主要的是用确切的路由键将WorkerExchange和WorkerQueue绑定。 应该通过RabbitMq UI Manager为work.exchange配置它。

然后使用此路由密钥通过WorkerExchange将消息添加到WorkerQueue。 然后,这些“死队列”消息将存储在retry.queue

中。
channel.QueueDeclare
            (
                WorkerQueue, true, false, false,
                new Dictionary<string, object>
                {
                    {"x-dead-letter-exchange", RetryExchange}
                }
            );

这是C#代码中队列声明所需要的。

不需要额外的参数{"x-dead-letter-routing-key", RetryQueue}

也不需要以下代码行:

channel.ExchangeDeclare(WorkerExchange, "direct");

channel.QueueBind(WorkerQueue, WorkerExchange, WorkerQueue, null);

channel.ExchangeDeclare(RetryExchange, "direct");
channel.QueueDeclare
            (
                RetryQueue, true, false, false,
                new Dictionary<string, object>
                {
                    {"x-dead-letter-exchange", WorkerExchange},
                    {"x-dead-letter-routing-key", WorkerQueue},
                    {"x-message-ttl", 30000},
                }
            );
channel.QueueBind(RetryQueue, RetryExchange, RetryQueue, null);

因此您可以删除上述行。