簡體   English   中英

在隊列中找不到MSMQ有毒消息

[英]MSMQ poison message not found in queue

在MSMQ隊列中遇到了帶有中毒消息的奇怪問題。 當檢測到中毒消息時,我正在使用下面的代碼來處理異常並將消息移至中毒隊列,但這失敗了,因為即使我從拋出的異常中獲取了它的lookupId,也未找到該消息。 請參閱下面的相關代碼。

public bool HandleError(Exception error)
{
    var poisonException = error as MsmqPoisonMessageException;
    if (null == poisonException) return false;

    var lookupId = poisonException.MessageLookupId;

    var queuePath = Environment.MachineName + "\\" + ConfigurationManager.AppSettings["QueuePath"];
    var poisonQueuePath = Environment.MachineName + "\\" + ConfigurationManager.AppSettings["PoisonQueuePath"];

    var orderQueue = new System.Messaging.MessageQueue(queuePath);
    var poisonMessageQueue = new System.Messaging.MessageQueue(poisonQueuePath);

    // Use a new transaction scope to remove the message from the main queue and add it to the poison queue.
    using (var txScope = new TransactionScope(TransactionScopeOption.RequiresNew))
    {
        int retryCount = 0;
        while (retryCount < 3)
        {
            retryCount++;

            try
            {
                // Try to get the poison message using the look up id. This line throws InvalidOperationException
                var message = orderQueue.ReceiveByLookupId(lookupId);
                // Send the message to the poison message queue.
                poisonMessageQueue.Send(message, System.Messaging.MessageQueueTransactionType.Automatic);

                txScope.Complete();

                Logger.Debug("Moved poisoned message with look up id: " + lookupId + " to poison queue: " + ConfigurationManager.AppSettings["PoisonQueuePath"]);
                break;
            }
            catch (InvalidOperationException e)
            {
                if (retryCount < 3)
                {
                    Logger.Debug("Trying to move message to poison queue but message is not available, sleeping for 10 seconds before retrying", e);
                    Thread.Sleep(TimeSpan.FromSeconds(10));
                }
                else
                {
                    Logger.Debug("Giving up on trying to move the message", e);
                }
            }
        }
    }

    Logger.Info("Restarting the service to process rest of the messages in the queue");
    WaitCallback restartCallback = new WaitCallback(Start);
    ThreadPool.QueueUserWorkItem(restartCallback);

    return true;
}

該代碼基本上是從Microsoft的示例代碼在此處復制的。

引發的錯誤是正確的類型:

System.ServiceModel.MsmqPoisonMessageException: The transport channel detected a poison message.

但是,當嘗試從隊列中獲取消息時,我得到了:

System.InvalidOperationException: Message requested was not found in the queue specified.

我首先想到的是,隊列可能沒有設置正確的權限,但是我仔細檢查了網絡服務用戶是否具有讀寫消息到兩個隊列的所有必要權限。

值得一提的是,該代碼已經在生產環境中完美運行了幾個月,並且在過去的許多有毒消息中幸免於難。 非常感謝任何可能導致此問題的輸入。

當您指定了多個重試周期時,就會發生這種情況。 如果maxRetryCycles大於零,並且retryCycleDelay大於30秒,則將看到您描述的問題。 該消息實際上位於一個稱為“重試”的子隊列中,因為它在周期之間等待retryCycleDelay。 因此,當您的IErrorHandler在“主”隊列中查找它時,將找不到它。 由於某些原因,WCF在每個重試周期結束時引發MsmqPoisonMessageException,而不僅僅是在所有重試周期結束時引發一次。 這意味着您的IErrorHandler將在每個周期結束時調用。 對我來說似乎真的很奇怪,但是事實就是這樣。

現在,更好的方法(如果可以保證您的代碼將具有MSMQ 4.0)是將receiveErrorHandling從“ Fault”更改為“ Move”,然后擺脫IErrorHandler。 通過這種方法,在所有重試和重試周期完成后,將為您移動郵件。 它被移到稱為“毒葯”的子隊列中。

請參閱此處以獲取更多詳細信息:

MSMQ 4.0中的毒葯消息處理

暫無
暫無

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

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