簡體   English   中英

Rabbit MQ unack 消息未返回隊列供消費者再次處理

[英]Rabbit MQ unack message not back to queue for consumer to process again

我使用 RabbitMQ 作為我的隊列消息服務器,我使用 .NET C# 客戶端。 當處理來自隊列的消息出現錯誤時,消息不會確認並且仍然卡在隊列中,不會像我理解的文檔那樣再次處理。

我不知道我是否錯過了一些配置或代碼塊。

我現在的想法是如果錯誤並手動將此消息再次推送到隊列中,則自動手動確認消息。

我希望有另一個更好的解決方案。

太感謝了。

我的代碼

        public void Subscribe(string queueName)
    {
        while (!Cancelled)
        {
            try
            {
                if (subscription == null)
                {
                    try
                    {
                        //try to open connection
                        connection = connectionFactory.CreateConnection();
                    }
                    catch (BrokerUnreachableException ex)
                    {
                        //You probably want to log the error and cancel after N tries, 
                        //otherwise start the loop over to try to connect again after a second or so.
                        log.Error(ex);
                        continue;
                    }

                    //crate chanel
                    channel = connection.CreateModel();
                    // This instructs the channel not to prefetch more than one message
                    channel.BasicQos(0, 1, false);
                    // Create a new, durable exchange
                    channel.ExchangeDeclare(exchangeName, ExchangeType.Direct, true, false, null);
                    // Create a new, durable queue
                    channel.QueueDeclare(queueName, true, false, false, null);
                    // Bind the queue to the exchange
                    channel.QueueBind(queueName, exchangeName, queueName);
                    //create subscription
                    subscription = new Subscription(channel, queueName, false);
                }

                BasicDeliverEventArgs eventArgs;
                var gotMessage = subscription.Next(250, out eventArgs);//250 millisecond
                if (gotMessage)
                {
                    if (eventArgs == null)
                    {
                        //This means the connection is closed.
                        DisposeAllConnectionObjects();
                        continue;//move to new iterate
                    }

                    //process message

                   channel.BasicAck(eventArgs.DeliveryTag, false);


                }
            }
            catch (OperationInterruptedException ex)
            {
                log.Error(ex);
                DisposeAllConnectionObjects();
            }
        }

        DisposeAllConnectionObjects();
    }

    private void DisposeAllConnectionObjects()
    {
        //dispose subscription
        if (subscription != null)
        {
            //IDisposable is implemented explicitly for some reason.
            ((IDisposable)subscription).Dispose();
            subscription = null;
        }

        //dipose channel
        if (channel != null)
        {
            channel.Dispose();
            channel = null;
        }

        //check if connection is not null and dispose it
        if (connection != null)
        {
            try
            {
                connection.Dispose();
            }
            catch (EndOfStreamException ex)
            {
                log.Error(ex);
            }
            catch (OperationInterruptedException ex)//handle this get error from dispose connection 
            {
                log.Error(ex);
            }
            catch (Exception ex)
            {
                log.Error(ex);
            }
            connection = null;
        }
    }

我認為您可能誤解了 RabbitMQ 文檔。 如果消息沒有得到消費者的確認,Rabbit broker 會將消息重新排入隊列以供消費。 我不相信您建議的確認然后重新排隊消息的方法是一個好主意,只會使問題變得更加復雜。

如果你想明確地“拒絕”一條消息,因為消費者在處理它時遇到了問題,你可以使用 Rabbit 的 Nack 特性。

例如,在您的 catch 異常塊中,您可以使用:

subscription.Model.BasicNack(eventArgs.DeliveryTag, false, true);

這將通知 Rabbit broker 重新排隊消息。 基本上,您傳遞傳遞標簽,false 表示它不是多條消息,true 表示重新排隊消息。 如果您想拒絕消息而不重新排隊,只需將 true 更改為 false。

此外,您已經創建了一個訂閱,所以我認為您應該直接對此執行確認,而不是通過頻道。

改變:

channel.BasicAck(eventArgs.DeliveryTag, false);

到:

subscription.Ack(); 

這種確認方法更簡潔,因為您將所有與訂閱相關的內容都保留在訂閱對象上,而不是搞亂您已經訂閱的頻道。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM