RabbitMQ重新处理死信队列

时间:2014-07-15 17:53:28

标签: c# rabbitmq

我正在寻找一种方法从兔子死信队列中取出物品并将它们处理回队列中。是否有内置的方法来做到这一点?

2 个答案:

答案 0 :(得分:0)

您可以使用与通常队列相同的方式来消费来自DLX(实际上来自DLQ)的消息。

你提出的建议(从DLQ获取消息并将其发布到队列中它最初是无法解决的)可能导致(并且通常会)消息循环。

最佳实践方式是以某种单独的方式处理无法复制的消息,或者根本不对它们进行过时的处理。

答案 1 :(得分:0)

我没有找到内置方法来做到这一点,所以我创建了自己的小解决方案。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using RabbitMQ.Client;
using RabbitMQ.Client.Framing.v0_9_1;

namespace RabbitMQReprocessDeadLetter
{
    public class RabbitReprocessor
    {
        private readonly IModel _model;
        private readonly string _deadLetterQueueName;
        private const ushort FetchSize = 10;
        private const string ConsumerName = "DeadLetterReprocessor";

        public RabbitReprocessor(IConnection rabbitConnection, string deadLetterQueueName)
        {
            _deadLetterQueueName = deadLetterQueueName;
            _model = rabbitConnection.CreateModel();
        }

        public void StartConsuming(CancellationTokenSource cancellationTokenSource = null)
        {
            // Configure the Quality of service for the model. Below is how what each setting means.
            // BasicQos(0="Dont send me a new message untill I’ve finshed",  _fetchSize = "Send me N messages at a time", false ="Apply to this Model only")
            _model.BasicQos(0, FetchSize, false);

            var queueingBasicConsumer = new QueueingBasicConsumer(_model);
            _model.BasicConsume(_deadLetterQueueName, false, ConsumerName, queueingBasicConsumer);

            while (true)
            {
                if (cancellationTokenSource != null && cancellationTokenSource.IsCancellationRequested)
                {
                    return;
                }

                var e = queueingBasicConsumer.Queue.Dequeue(); // blocking call
                var deathProperties = (List<object>) e.BasicProperties.Headers["x-death"];
                var prop = (Dictionary<string, object>)deathProperties.Single();
                var queueAsByteArray = (byte[])prop["queue"];
                var queueName = queueAsByteArray.ConvertToString();
                var data = e.Body;
                try
                {
                    Console.WriteLine("{0} => {1}", queueName, data.Deserialize<long>());
                }
                // ReSharper disable once EmptyGeneralCatchClause
                catch { }
                SendMessageToQueue(queueName, data);
                _model.BasicAck(e.DeliveryTag, false);
            }
        }

        /// <summary>
        /// delivery the message directly into the queue from which it came.
        /// 
        /// You may want to put it back into an exchange instead of a queue.
        /// </summary>
        private void SendMessageToQueue(string queueName, byte[] messageBytes)
        {
            const string exchangeName = "";
            if (string.IsNullOrEmpty(queueName))
            {
                throw new ArgumentNullException("queueName");
            }
            if (messageBytes == null)
            {
                throw new ArgumentNullException("messageBytes");
            }
            var basicProperties = new BasicProperties
            {
                DeliveryMode = 2//2 = durable
            };
            _model.BasicPublish(exchangeName, queueName, basicProperties, messageBytes);
        }
    }
}

完整的解决方案可以在这里找到:

https://github.com/jayhilden/RabbitMQReprocessDeadLetter