【问题标题】:MSMQ receive with transaction - rollback not making message available againMSMQ 接收事务 - 回滚不再使消息可用
【发布时间】: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 但此时我希望消息会返回到队列中。但是,这并没有发生,并且消息丢失了。

我是否遗漏了一些明显的东西?谁能看到我做错了什么?

【问题讨论】:

  • 你在本地接收到的队列是监听服务的吗?
  • 是的,发送和接收进程和队列都在同一个盒子上。他们是私人队列。我也在几个不同的盒子上运行了相同的代码,并且看到了同样的问题。这表明它与这段代码有关,而不是与机器有关。
  • 我猜这个问题很明显。您确定它在中止时遇到异常吗?是否有可能在您的消息处理代码中引发异常,该异常被捕获然后被丢弃,因此它永远不会冒泡到您的异常处理程序中,其中包含中止?

标签: c# .net transactions msmq message-queue


【解决方案1】:

感谢所有 cmets。我确实按照 Russell McClure 的建议重新组织了我的代码,并尝试创建简单的测试用例,但无法重现问题。

最后,问题根本不是我在寻找的地方(这种情况多久发生一次?)。

在我的管道中,我有一个重复的消息检查器。我的系统处理的“消息”来自 WAN 上的远程设备,有时网络上的消息是重复的。

当从 MSMQ 中提取消息时,它将通过重复检查器传递给数据库编写器。如果数据库编写器失败,则检查的副本不会从其表中删除散列。当进程再次尝试循环时,它会从队列 agan 中获得相同的消息,因为当数据库写入器失败时,MSMQ 事务已回滚。但是,在第二次尝试时,重复检查器会发现它以前看过该消息,然后默默地吞下它。

解决方法是让重复检查器发现来自链中下一个链接的异常,并回滚它所做的任何事情。

【讨论】:

    【解决方案2】:

    您的队列需要创建为事务队列才能获得您想要的。

    编辑:

    好吧,如果您的队列是事务性的,那么这表明您对事务处理不当,尽管我无法具体看到它是如何发生的。我会更改您的 BlockingReceive 方法以返回消息。我会将 MessageQueueTransaction 的创建移至外部方法。如果您在同一方法中调用 Begin、Commit 和 Abort 方法,您的代码将更易于维护。

    【讨论】:

    • 嗨!队列肯定是作为事务队列创建的。如果我查看计算机管理->服务和应用程序->消息队列中的队列属性,它显示为事务性。
    猜你喜欢
    • 2010-12-04
    • 1970-01-01
    • 1970-01-01
    • 2010-11-14
    • 2011-08-13
    • 1970-01-01
    • 2015-04-30
    • 2015-12-03
    • 2013-06-24
    相关资源
    最近更新 更多