繁体   English   中英

在 2PC 准备期间连接丢失后 JMS 消息未回滚

[英]JMS message not rolled back after connection lost during 2PC prepare

我正在尝试解决以下问题:

TL;DR 在准备 2PC 期间,当与队列管理器的连接丢失时,如何确保发生回滚。

  • 爪哇:8
  • 弹簧靴:2.3.12.RELEASE
  • spring-jms:5.2.20.RELEASE
  • mq-jms-spring-boot-starter: 2.6.5 (allclient: 9.2.5.0)
  • narayana spring boot starter:2.6.3(narayana:5.11.3.Final)
  • 嗅觉:3.1.12

==================================================== ========

  1. 应用程序正在从事务中的队列 X 读取持久消息(没有过期)
  2. 我在XAResouceRecord.topLevelPrepare中设置了一个断点,并使用 Sniffy 在 2PC 准备期间切断了与队列管理器的连接
  3. 我等待超过 HBINT (300) 时间(或关闭 VM 以立即断开 TCP 连接)
  4. 我希望消息在消息队列 X 上可用,它是退出队列或死信队列

但是,消息不会回滚。 我没有看到任何事务日志(我相信这是可以预料的,因为准备工作没有完成)。 队列或回退队列上没有未提交的消息。

如果我在接收到消息之后但在事务提交之前在AbstractPollingMessageListenerContainer.receiveAndExecute中放置一个断点,我可以看到该消息不再在队列中。 所以看起来 session.commit 是否已经发生。 在准备 2PC 期间,当与队列管理器的连接丢失时,如何确保发生回滚。 我可能在这里遗漏了一些东西,但我看不出是什么。

经过更多的挖掘,我相信我找到了问题所在。 现在,当我在准备 2PC 期间断开与队列管理器的连接时,消息会回滚。 希望这可能对其他人有所帮助。

在我的问题中,我提到在AbstractPollingMessageListenerContainer.receiveAndExecute中放置一个断点。 在我使用 5.2.20.RELEASE 的春季版本中,代码如下所示:

        if (this.transactionManager != null) {
            // Execute receive within transaction.
            TransactionStatus status = this.transactionManager.getTransaction(this.transactionDefinition);
            boolean messageReceived;
            try {
                messageReceived = doReceiveAndExecute(invoker, session, consumer, status);
            }
            catch (JMSException | RuntimeException | Error ex) {
                rollbackOnException(this.transactionManager, status, ex);
                throw ex;
            }
            this.transactionManager.commit(status);
            return messageReceived;
        }

这看起来有点奇怪,因为transactionManager.commit没有被 try catch 包围。 那么如果提交失败会发生什么?

try-catch 是在 5.3.16 中添加的,见https://github.com/spring-projects/spring-framework/pull/1807

        if (this.transactionManager != null) {
            // Execute receive within transaction.
            TransactionStatus status = this.transactionManager.getTransaction(this.transactionDefinition);
            boolean messageReceived;
            try {
                messageReceived = doReceiveAndExecute(invoker, session, consumer, status);
            }
            catch (JMSException | RuntimeException | Error ex) {
                rollbackOnException(this.transactionManager, status, ex);
                throw ex;
            }
            try {
                this.transactionManager.commit(status);
            }
            catch (TransactionException ex) {
                // Propagate transaction system exceptions as infrastructure problems.
                throw ex;
            }
            catch (RuntimeException ex) {
                // Typically a late persistence exception from a listener-used resource
                // -> handle it as listener exception, not as an infrastructure problem.
                // E.g. a database locking failure should not lead to listener shutdown.
                handleListenerException(ex);
            }
            return messageReceived;
        }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM