简体   繁体   English

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

[英]Rabbit-Mq not routing to dead letter queue after being rejected

I'm currently playing around with Rabbit-Mq, and am trying to implement a "dead-letter" queue, a queue for failed messages. 我正在玩Rabbit-Mq,我正在尝试实现一个“死信”队列,一个失败消息的队列。 I've been reading the rabbit documentation: https://www.rabbitmq.com/dlx.html . 我一直在阅读兔子文档: https//www.rabbitmq.com/dlx.html

and have come up with this example: 并提出了这个例子:

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();
            }
        }
    }
}

Image of queue when publishing to worker queue: 发布到工作队列时的队列映像: rabbit-mq worker queue stats

Image of the retry queue: 重试队列的图像: rabbit-mq重试统计数据

I feel as though I'm missing some small details but can't seem to find what they are. 我觉得好像我错过了一些小细节,但似乎无法找到它们是什么。

Thanks in advance 提前致谢

You should define your dead-letter-exchange as fanout . 您应该将死信交换定义为fanout

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

If your dead letter exchange is setup as DIRECT you must specify a dead letter routing key. 如果您的死信交换设置为DIRECT,则必须指定死信路由密钥。 If you just want all your NACKed message to go into a dead letter bucket for later investigation (as I do) then your dead letter exchange should be setup as a FANOUT. 如果您只是希望所有NACKed消息进入死信桶以供以后调查(就像我一样)那么您的死信交换应设置为FANOUT。

Look at this for more info 请查看此信息以获取更多信息

Turns out that if a dead letter exchange is a direct exchange then the queue parameters require a x-dead-letter-routing-key . 事实证明,如果死信交换是direct交换,则队列参数需要x-dead-letter-routing-key Above (in the question) I am using this key in the dictionary to try and route my messages but what I am not doing is adding a route to my binding, here is an updated version of the code that works: 上面(在问题中)我在字典中使用这个键来尝试路由我的消息但是我没做的是添加一个到我的绑定的路由,这里是一个有效的代码的更新版本:

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();
            }
        }
    }

The difference being that the call to channel.QueueBind(WorkerQueue, WorkerExchange, WorkerQueue, null); 不同之处在于调用channel.QueueBind(WorkerQueue, WorkerExchange, WorkerQueue, null); now supplies the routing key to be the same as the queuename, so when the message "dead-letters" it gets routed to the exchange via this key 现在提供的路由密钥与queuename相同,所以当消息“dead-letters”时,它会通过这个密钥路由到交换机

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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