繁体   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