1

我有一个 Windows 服务,它通过为 MSMQ peekCompleted 事件提供处理程序来监视私有 MSMQ 的消息,如下所示(在服务 OnStart 期间分配):

_queue.PeekCompleted += new PeekCompletedEventHandler(MessageReceived);

然后 MessageReceived 方法执行此操作(以下划线开头的变量在服务中全局声明):

 private void MessageReceived(object sender, PeekCompletedEventArgs e)
    {
        try
        {
            _handler = new MessageHandler(); //does the heavy lifting
            _queueMessage = _queue.EndPeek(e.AsyncResult);
            _queueMessage.Formatter = new BinaryMessageFormatter();
            _currentMessage = (MyMessageType)_queueMessage.Body;

            // we have the message so no matter what we want it off of the queue
            _queue.ReceiveById(_queueMessage.Id);

            // Message Handler is going to swallow everything here
            // messages are processed OK or moved to a 'failed' or 'poison' queue
            // there should be no uncaught exceptions
            _handler.Process(_currentMessage);

            //go wait again
            _queue.BeginPeek();
        }
        catch (Exception exception)
        {
           // here is question

        }
    }

问题:鉴于 _handler 吞下了它生成/遇到的任何异常(并相应地处理其消息),我不希望在这个 try 块中出现异常,但如果确实发生了任何异常,我需要确保队列返回到正确的状态,即使我不知道异常可能发生在哪里。我也是

 _queue.ReceiveById(_queueMessage.Id);
 _queue.BeginPeek();

在 catch 块中,即使这两个语句中的任何一个可能已经被执行?我不能真的假设(咳咳)其中一个没有出于某种未知原因生成异常,这是异常的性质,是吗?

这应该如何处理?

4

1 回答 1

2

不要处理它。如果您使队列具有事务性,则可以将 ReceiveById 调用包装在事务中。:

using (TransactionScope txnScope = new TransactionScope())
{
    _queue.ReceiveById(_queueMessage.Id);
    txnScope.Commit();
}

这将确保如果在提交之前引发异常,则消息将留在队列中。这仅在您接收来自本地的队列时才有效。否则,您需要在所有相关机器上配置 DTC。

于 2013-10-01T10:07:05.797 回答