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 接收事务 - 回滚不再使消息可用的主要内容,如果未能解决你的问题,请参考以下文章

MSMQ 事务性消息传递如何工作?

如何在C#中使用MSMQ

如何在使用 WCF 的事务性 MSMQ 中将消息显式标记为中毒

消息队列MSMQ的使用

我们如何加快从 MSMQ 接收消息的速度?

两次接收相同的 MSMQ 消息?