2014-01-20 174 views
2

這裏就是我想要做:basic.Nack沒有得到處理

  1. 出隊的消息
  2. 做與消息
  3. 如果操作失敗的動作,把消息發回的排隊
  4. 如果操作成功,確認該消息

我的問題現在的問題是,如果行動失敗,該消息不重新入隊,但保持未確認。如果我進入RabbitMQ網頁配置界面,我會發現郵件被標記爲未確認,即使basic.Nack已經被移除。

var delivery = subscription.Next(); 

var messageBody = delivery.Body; 

try 
{ 
    action.Invoke(messageBody); 
    subscription.Ack(delivery); 
} 
catch (Exception ex) 
{ 
    subscription.Model.BasicNack(delivery.DeliveryTag, false, true); 
    throw ex; 
} 

更新:

所以我已經注意到,從消息準備去未確認的真快。速度更快,然後我實際上調用subscriber.Next(),好像.Net客戶端將所有消息緩存在內存中(應用程序的內存足跡實際上增長得相當快),並從內存中處理這些消息然後發送Ack(),從Unacknowledged中解除消息。

更新2:

好像隊列被清空的真快,是因爲我沒有設置我的模型BasicQos。以下固定了一切。 Basic.Nack()似乎仍不到壽工作:

Model.BasicQos(0,1,FALSE)

回答

1

我懷疑你使用:
channel.BasicConsume(your_queue_name, false, consumer);檢索郵件。

我用RabbitMQ 3.2.4服務器和客戶端運行了幾次測試。我無法得到channel.BasickAck(...)channel.BasicNack(...)按預期工作。

這就是說,我能夠得到預期的Ack |我使用的Nack行爲:
BasicGetResult result = channel.BasicGet(your_queue_name, false);

所以你可能想要考慮一種不同的檢索方法來獲取消息。我意識到消費& Dequeue是「首選」的方法,但他們沒有在我的情況下工作。我希望公平,一次性發送確認。使用BasicGet是我能做到的唯一方法。

該方法的缺點是您可能會丟失與subscription.Next()一起使用的客戶端事件迭代器。


如果我不得不冒險猜測,我認爲關於本地Queue集合的一些事情正在混淆通道提供確認的能力。值得指出的是,使用new QueueingBasicConsumer(channel);創建消費者會觸發從服務器隊列中預取事件的調用。消費者隊列只是SharedQueue<RabbitMQ.Client.Events.BasicDeliverEventArgs>,SharedQueue只是IEnumerable的擴展。

另外請記住,拉動消息的同一個通道需要提供Ack | NACK。 你不能Ack | Nack來自不同渠道的消息。或者至少我還沒有想出如何這樣做,也沒有其他人。如果你在使用語句中包裝你的RabbitMQ對象,那麼這是一個問題(所以你不要留下網絡資源)你需要很長的過程才能安全地確認。

SO Answer勾畫出一個像樣的工作流程,以避開可能的現實,你拉頻道將是發送ACK頻道| NACK。訣竅在於設置一個TTL並且不會爲發送Nack而煩惱 - 只需讓新消息自動過期並重新發送即可。