You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ActiveMQ Artemis PostgreSQL断连恢复后报Session is closed异常

ActiveMQ Artemis 2.21.0 JDBC存储模式下数据库断连后无法恢复问题排查

问题背景

  • 嵌入式集成Spring Java Web应用的ActiveMQ Artemis从1.5.3升级至2.21.0,存储方案从文件系统切换为PostgreSQL JDBC存储
  • 预期PostgreSQL临时断连恢复后,JMS队列收发可正常执行,实际抛出Session is closed异常

复现流程

  1. 启动应用服务
  2. 关停PostgreSQL数据库
  3. 执行JMS队列消息发送/读取操作,操作失败符合预期
  4. 重启PostgreSQL恢复数据库连接
  5. 再次执行JMS队列消息发送/读取操作,操作异常

异常与现有配置

核心异常栈

javax.jms.IllegalStateRuntimeException: Session is closed
    at org.apache.activemq.artemis.jms.client.JmsExceptionUtils.convertToRuntimeException(JmsExceptionUtils.java:59)
    at org.apache.activemq.artemis.jms.client.ActiveMQJMSContext.createMapMessage(ActiveMQJMSContext.java:257)
    at com..data.core.messaging.dataload.BaseDataLoaderMessageSender.getMapMessage(BaseDataLoaderMessageSender.java:220)
    at com.test.data.core.messaging.dataload.BaseDataLoaderMessageSender.send(BaseDataLoaderMessageSender.java:140)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: javax.jms.IllegalStateException: Session is closed
    at org.apache.activemq.artemis.jms.client.ActiveMQSession.checkClosed(ActiveMQSession.java:1255)
    at org.apache.activemq.artemis.jms.client.ActiveMQSession.createMapMessage(ActiveMQSession.java:169)
    at org.apache.activemq.artemis.jms.client.ActiveMQJMSContext.createMapMessage(ActiveMQJMSContext.java:255)
    ... 132 more

现有配置

  1. Spring配置的ConnectionFactory:
<bean id="queueConnectionFactory"
      class="org.apache.activemq.artemis.jms.client.ActiveMQJMSConnectionFactory">
    <constructor-arg value="false"/>
    <constructor-arg>
        <bean class="org.apache.activemq.artemis.api.core.TransportConfiguration">
            <constructor-arg
                    value="org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory"/>
        </bean>
    </constructor-arg>
    <property name="ConsumerWindowSize" value="0"/>
</bean>
  1. 客户端初始化逻辑:
jmsContext = connectionFactory.createContext();
producer = jmsContext.createProducer();

已尝试异常时编程重建ConnectionFactory,问题未解决。

补充现象

  1. 数据库断连时,JDBC存储同步失败触发Critical IO Error,Broker自动关停,所有客户端连接、Session、Consumer被关闭;数据库恢复后Broker未自动重启,未调用stop直接调用start会抛出无法连接服务端异常:
[ERROR] 2022-06-24 10:29:11.737 [Thread-6] JDBCConnectionProvider - SQL EXCEPTIONS: SQLState: 08001 连接localhost:5432被拒绝
[WARN ] 2022-06-24 10:29:11.833 [Thread-6] server - AMQ222010: Critical IO Error, shutting down the server. Failed to process JDBC Record statements
[INFO ] 2022-06-24 10:30:04.019 [Thread-12] load - deActivate called
[WARN ] 2022-06-24 10:30:04.112 [client线程] client - AMQ212037: Connection failure to invm:0 : AMQ219015: The connection was disconnected because of server shutdown [code=DISCONNECTED]
[ERROR] 消费线程报AMQ219017: Consumer is closed、AMQ219019: Session is closed异常

直接启动异常栈:

Caused by: javax.jms.JMSException: Failed to create session factory
    at org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory.createConnectionInternal(ActiveMQConnectionFactory.java:867)
Caused by: org.apache.activemq.artemis.api.core.ActiveMQNotConnectedException: AMQ219007: Cannot connect to server(s). Tried with all available servers.
    at org.apache.activemq.artemis.core.client.impl.ServerLocatorImpl.createSessionFactory(ServerLocatorImpl.java:703)
  1. 停止服务时偶现线程TIMED_WAITING阻塞在文件锁获取逻辑:
Thread-6
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:446)
at org.apache.activemq.artemis.core.server.impl.FileLockNodeManager.lock(FileLockNodeManager.java:442)
at org.apache.activemq.artemis.core.server.impl.FileLockNodeManager.pauseLiveServer(FileLockNodeManager.java:269)
at org.apache.activemq.artemis.core.server.impl.LiveOnlyActivation.close(LiveOnlyActivation.java:104)
at org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl.stop(ActiveMQServerImpl.java:1393)
at org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ.stop(EmbeddedActiveMQ.java:168)

根因分析

  • Broker侧默认策略问题:Artemis默认将JDBC存储层抛出的IO异常判定为致命临界错误,触发后直接执行Broker关停流程,无内置的数据库恢复后自动重启机制。异常关停时Broker没有走完完整的生命周期清理流程,残留文件锁、内部服务状态未重置,直接调用start会触发锁冲突、状态校验失败,无法正常启动。
  • 客户端侧对象失效问题:当前JMSContext、MessageProducer为应用启动时初始化的单例对象,Broker关停后这些对象已进入closed状态,即便后续Broker重启,旧对象持有的会话引用也不会自动恢复。仅重建ConnectionFactory无法替换已经失效的Context、Producer实例,因此操作持续报错。
  • 文件锁阻塞问题:异常关停时FileLockNodeManager持有的锁未被正常释放,重启时锁等待逻辑默认无超时限制,进入循环睡眠等待,导致线程阻塞在TIMED_WAITING状态。

解决方案

Broker侧配置与生命周期管控

  1. 调整临界错误处理策略,避免JDBC临时断连直接触发Broker关停。在EmbeddedActiveMQ的配置中添加以下参数,将临界错误响应改为记录日志而非关停服务:
    <critical-analyzer-policy>LOG</critical-analyzer-policy>
    <critical-analyzer-check-period>5000</critical-analyzer-check-period>
    <critical-analyzer-timeout>30000</critical-analyzer-timeout>
    
    同时JDBC层使用带连接检测、自动重连的连接池(如HikariCP),配置连接测试查询、合理的连接超时和重试间隔,优先在JDBC层消化临时连接中断异常,避免异常透传给Artemis临界分析器。
  2. 实现Broker安全重启逻辑。增加Broker状态定时检测任务,当检测到Broker异常停止、且数据库连接恢复正常时,严格按照「先执行完整stop流程→等待所有服务线程终止、文件锁释放→再执行start」的流程拉起Broker,禁止在Broker未完成清理时直接调用start。
  3. 修复文件锁阻塞问题,配置文件锁超时时间:
    <file-lock-timeout>5000</file-lock-timeout>
    
    锁等待超时后强制释放残留锁,避免线程无限阻塞。

客户端侧调整

  1. 废弃JMSContext、MessageProducer的单例初始化逻辑。每次执行消息收发操作前检测会话状态,捕获到Session is closed/Consumer is closed异常时,直接销毁旧实例,重新从ConnectionFactory创建新的JMSContext、Producer/Consumer实例后重试操作。
  2. 为InVM连接配置客户端重试参数,修改ConnectionFactory配置,添加以下属性:
    <property name="retryInterval" value="1000"/>
    <property name="retryAttempts" value="10"/>
    <property name="failoverOnInitialConnection" value="false"/>
    <property name="clientFailureCheckPeriod" value="2000"/>
    
    让客户端在Broker重启窗口期自动重试连接,减少临时异常抛出。

验证效果

按照原有复现流程操作:关停PostgreSQL时消息收发返回临时失败,数据库恢复、Broker正常拉起后,客户端重建会话即可正常执行消息收发,无Session is closed异常;服务停止时不会出现文件锁阻塞问题。

内容的提问来源于stack exchange,提问作者Vishal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 00:33:21