MSMQ 接收事务 - 回滚不再使消息可用
Posted
技术标签:
【中文标题】MSMQ 接收事务 - 回滚不再使消息可用【英文标题】:MSMQ receive with transaction - rollback not making message available again 【发布时间】:2011-12-29 22:57:25 【问题描述】:我在一个名为“MessageQueueReceive”的类中有这个。
public MessageQueueTransaction BlockingReceive(out Message message)
MessageQueueTransaction tran = null;
message = null;
tran = new MessageQueueTransaction();
tran.Begin();
try
message = Queue.Receive(new TimeSpan(0, 0, 5), tran);
catch (MessageQueueException ex)
// If the exception was a timeout, then just continue
// otherwise re-raise it.
if (ex.MessageQueueErrorCode != MessageQueueErrorCode.IOTimeout)
throw ex;
return tran;
然后我的处理循环有这个:-
while (!Abort)
try
tran = this.Queue.BlockingReceive(out msg);
if (msg != null)
// Process message here
if (tran != null)
tran.Commit();
catch (Exception ex)
if (tran != null)
tran.Abort();
控制面板工具显示我正在使用的消息队列是事务性的。日志队列未启用。
此代码创建队列:-
private static MessageQueue CreateMessageQueue(string queueName, bool transactional = false)
MessageQueue messageQueue = MessageQueue.Create(queueName, transactional);
messageQueue.SetPermissions("Administrators", MessageQueueAccessRights.FullControl,
AccessControlEntryType.Allow);
return messageQueue;
调用时事务参数设置为“true”。
我发现,当在消息处理过程中发生异常时,会调用 tran.Abort 但此时我希望消息会返回到队列中。但是,这并没有发生,并且消息丢失了。
我是否遗漏了一些明显的东西?谁能看到我做错了什么?
【问题讨论】:
你在本地接收到的队列是监听服务的吗? 是的,发送和接收进程和队列都在同一个盒子上。他们是私人队列。我也在几个不同的盒子上运行了相同的代码,并且看到了同样的问题。这表明它与这段代码有关,而不是与机器有关。 我猜这个问题很明显。您确定它在中止时遇到异常吗?是否有可能在您的消息处理代码中引发异常,该异常被捕获然后被丢弃,因此它永远不会冒泡到您的异常处理程序中,其中包含中止? 【参考方案1】:感谢所有 cmets。我确实按照 Russell McClure 的建议重新组织了我的代码,并尝试创建简单的测试用例,但无法重现问题。
最后,问题根本不是我在寻找的地方(这种情况多久发生一次?)。
在我的管道中,我有一个重复的消息检查器。我的系统处理的“消息”来自 WAN 上的远程设备,有时网络上的消息是重复的。
当从 MSMQ 中提取消息时,它将通过重复检查器传递给数据库编写器。如果数据库编写器失败,则检查的副本不会从其表中删除散列。当进程再次尝试循环时,它会从队列 agan 中获得相同的消息,因为当数据库写入器失败时,MSMQ 事务已回滚。但是,在第二次尝试时,重复检查器会发现它以前看过该消息,然后默默地吞下它。
解决方法是让重复检查器发现来自链中下一个链接的异常,并回滚它所做的任何事情。
【讨论】:
【参考方案2】:您的队列需要创建为事务队列才能获得您想要的。
编辑:
好吧,如果您的队列是事务性的,那么这表明您对事务处理不当,尽管我无法具体看到它是如何发生的。我会更改您的 BlockingReceive 方法以返回消息。我会将 MessageQueueTransaction 的创建移至外部方法。如果您在同一方法中调用 Begin、Commit 和 Abort 方法,您的代码将更易于维护。
【讨论】:
嗨!队列肯定是作为事务队列创建的。如果我查看计算机管理->服务和应用程序->消息队列中的队列属性,它显示为事务性。以上是关于MSMQ 接收事务 - 回滚不再使消息可用的主要内容,如果未能解决你的问题,请参考以下文章