簡體   English   中英

在Azure Service Bus上的死信隊列中完成一條消息

[英]Complete a message in a dead letter queue on Azure Service Bus

我希望能夠從我的死信隊列中刪除選定的郵件。

這是如何完成的?

我不斷收到錯誤:

由於RecieveContext為Null,因此無法完成操作

我嘗試了所有我能想到和閱讀的方法,這就是我現在所處的位置:

public void DeleteMessageFromDeadletterQueue<T>(string queueName, long sequenceNumber)
        {
     var client = GetQueueClient(queueName, true);
                var messages = GetMessages(client);
                foreach(var m in messages)
                {
                    if(m.SequenceNumber == sequenceNumber)
                    {
                        m.Complete();
                    }
                    else
                    {
                        m.Abandon();
                    }
                }
}

/// <summary>
        /// Return a list of all messages in a Queue
        /// </summary>
        /// <param name="client"></param>
        /// <returns></returns>
        private IEnumerable<BrokeredMessage> GetMessages(QueueClient client)
        {
            var peekedMessages = client.PeekBatch(0, peekedMessageBatchCount).ToList();
            bool getmore = peekedMessages.Count() == peekedMessageBatchCount ? true : false;

            while (getmore)
            {
                var moreMessages = client.PeekBatch(peekedMessages.Last().SequenceNumber, peekedMessageBatchCount);
                peekedMessages.AddRange(moreMessages);
                getmore = moreMessages.Count() == peekedMessageBatchCount ? true : false;
            }

            return peekedMessages;
        }

不知道為什么這似乎是一項如此艱巨的任務。

這里的問題是你調用了PeekBatch,它返回剛剛查看過的消息。 沒有接收上下文,您可以使用它來完成或放棄該消息。 Peek和PeekBatch操作僅返回消息,並且根本不鎖定它們,即使receiveMode設置為PeekLock也是如此。 它主要用於瀏覽隊列,但您無法對其進行操作。 請注意Abandon和Complete狀態的文檔,“只能在使用Peek-Lock ReceiveMode中運行的接收器接收到的消息上調用”。 這里不太清楚,但Peek和PeekBatch操作不計入其中,因為它們實際上並沒有獲得接收上下文。 這就是為什么當你試圖調用放棄時失敗的原因。 如果你真的找到了你正在尋找的那個,當你調用Complete時會拋出一個不同的錯誤。

你想要做的是在PeekBatch RecieveMode中使用ReceiveBatch操作。 這實際上會將一批消息拉回來,然后當您查看它們以找到您想要的消息時,實際上可以影響消息的完成。 當您觸發放棄時,它將立即釋放不是您想要返回隊列的消息。

如果您的死信隊列非常小,通常這也不錯。 如果它真的很大,那么采用這種方法並不是最有效的。 您將死信隊列更像堆,並通過它來處理,而不是“按順序”處理消息。 這在處理需要人工干預的死信隊列時並不少見,但是如果你有很多這樣的話,那么將死​​信隊列處理成不同類型的商店可能會更容易找到,銷毀消息,但仍然可以重新創建可以推送到不同隊列進行重新處理的消息。

可能還有其他選項,例如使用Defer,如果您手動對文字進行刻字。 請參見如何在ServiceBus上使用sequenceNumber使用MessageReceiver.Receive方法

我沒有成功使用MikeWo的建議,因為當我使用將DLQ QueueClient與ReceiveMode.PeekLock實例化並使用ReceiveBatch拉取消息的組合時,我正在使用Receive / ReceiveBatch的版本通過其SequenceNumber請求消息。

[旁白:在我的應用程序中,我查看所有消息並列出它們,然后讓另一個處理程序根據它的特定序列號重新排隊到主隊列中的死信消息...]

但是對DLQClient上的Receive(long sequenceNumber)或ReceiveBatch(IEnumerable sequenceNumber)的調用總是拋出異常,“無法鎖定一條或多條指定的消息。消息不存在。” (即使我只通過1並且它肯定在隊列中)。

此外,由於原因不明確,使用ReceiveBatch(int messageCount),無論使用什么值作為messageCount,始終只返回隊列中的下一條消息。

最終對我有用的是以下內容:

QueueClient queueClient, deadLetterClient;
GetQueueClients(qname, ReceiveMode.PeekLock, out queueClient, out deadLetterClient);

BrokeredMessage msg = null;
var mapSequenceNumberToBrokeredMessage = new Dictionary<long, BrokeredMessage>();
while (msg == null)
{
#if UseReceive
    var message = deadLetterClient.Receive();
#elif UseReceiveBatch
    var messageEnumerable = deadLetterClient.ReceiveBatch(CnCountOfMessagesToPeek).ToList();
    if ((messageEnumerable == null) || (messageEnumerable.Count == 0))
        break;
    else if (messageEnumerable.Count != 1)
        throw new ApplicationException("Invalid expectation that there'd always be only 1 msg returned by ReceiveBatch");

    // I've yet to get back more than one in the deadletter queue, but... 
    var message = messageEnumerable.First();
#endif
    if (message.SequenceNumber == lMessageId)
    {
        msg = message;
        break;
    }
    else if (mapSequenceNumberToBrokeredMessage.ContainsKey(message.SequenceNumber))
    {
        // this means it's started the list over, so we didn't find it...
        break;
    }
    else
        mapSequenceNumberToBrokeredMessage.Add(message.SequenceNumber, message);
    message.Abandon();
}                        

if (msg == null)
    throw new ApplicationException("Unable to find a message in the deadletter queue with the SequenceNumber: " + msgid);

var strMessage = GetMessage(msg);
var newMsg = new BrokeredMessage(strMessage);
queueClient.Send(newMsg);

msg.Complete();

暫無
暫無

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

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