簡體   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