我有一个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块中,即使这两个语句中的任何一个可能已经被执行过了?我不能真的假设(咳咳)其中一个因某些未知原因而没有产生异常,这是异常的本质,是吗?
应如何处理?
答案 0 :(得分:2)
不要处理它。如果您使队列成为事务性的,那么您可以在事务中包装ReceiveById调用。:
using (TransactionScope txnScope = new TransactionScope())
{
_queue.ReceiveById(_queueMessage.Id);
txnScope.Commit();
}
这将确保如果在提交之前抛出异常,则消息将保留在队列中。这仅在您接收的队列是本地队列时才有效。否则,您需要在所有涉及的机器上配置DTC。