简体   繁体   English

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

[英]MSMQ poison message not found in queue

Have encounted a strange issue with poisoned messages in an MSMQ queue. 在MSMQ队列中遇到了带有中毒消息的奇怪问题。 When a poisoned message is detected I'm using the code below to handle the exception and move the message to the poison queue, but this fails because the message is not found even though I get its lookupId from the thrown exception. 当检测到中毒消息时,我正在使用下面的代码来处理异常并将消息移至中毒队列,但这失败了,因为即使我从抛出的异常中获取了它的lookupId,也未找到该消息。 See relevant code below. 请参阅下面的相关代码。

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;
}

This code is basically copied from Microsoft's example code here . 该代码基本上是从Microsoft的示例代码在此处复制的。

The error thrown is of the correct type: 引发的错误是正确的类型:

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

But when attempting to get the message from the queue I get: 但是,当尝试从队列中获取消息时,我得到了:

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

My first thought was that the queues might not have the correct permissions set but I've double checked that the Network Service user has all the necessary rights to read and write messages to both queues. 我首先想到的是,队列可能没有设置正确的权限,但是我仔细检查了网络服务用户是否具有读写消息到两个队列的所有必要权限。

It's worth mentioning that this code has been working perfectly in production for months, and has survived many poisoned messages in the past. 值得一提的是,该代码已经在生产环境中完美运行了几个月,并且在过去的许多有毒消息中幸免于难。 Any input on what might have caused this issue is greatly appreciated. 非常感谢任何可能导致此问题的输入。

This will happen when you have more than one retry cycle specified. 当您指定了多个重试周期时,就会发生这种情况。 If your maxRetryCycles is greater than zero and your retryCycleDelay is greater than 30 seconds, you will see the problem you describe. 如果maxRetryCycles大于零,并且retryCycleDelay大于30秒,则将看到您描述的问题。 The message is actually sitting in a subqueue called "retry" as it waits the retryCycleDelay between cycles. 该消息实际上位于一个称为“重试”的子队列中,因为它在周期之间等待retryCycleDelay。 So when your IErrorHandler looks for it in the "main" queue, it won't find it. 因此,当您的IErrorHandler在“主”队列中查找它时,将找不到它。 For some reason, WCF throws the MsmqPoisonMessageException at the end of each retry cycle, NOT just once at the end of all the retry cycles. 由于某些原因,WCF在每个重试周期结束时引发MsmqPoisonMessageException,而不仅仅是在所有重试周期结束时引发一次。 Which means that your IErrorHandler will get called at the end of each cycle. 这意味着您的IErrorHandler将在每个周期结束时调用。 Seems really strange to me but that's the way it is. 对我来说似乎真的很奇怪,但是事实就是这样。

A better approach now days (if you can guarantee that your code will have MSMQ 4.0) is to change your receiveErrorHandling from "Fault" to "Move" and then get rid of your IErrorHandler. 现在,更好的方法(如果可以保证您的代码将具有MSMQ 4.0)是将receiveErrorHandling从“ Fault”更改为“ Move”,然后摆脱IErrorHandler。 With that approach the messages will be moved for you after all the retries and retry cycles have completed. 通过这种方法,在所有重试和重试周期完成后,将为您移动邮件。 It is moved to a subqueue called "poison". 它被移到称为“毒药”的子队列中。

See here for more details: 请参阅此处以获取更多详细信息:

Poison Message Handling in MSMQ 4.0 MSMQ 4.0中的毒药消息处理

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM