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异常
复现流程
- 启动应用服务
- 关停PostgreSQL数据库
- 执行JMS队列消息发送/读取操作,操作失败符合预期
- 重启PostgreSQL恢复数据库连接
- 再次执行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
现有配置
- 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>
- 客户端初始化逻辑:
jmsContext = connectionFactory.createContext(); producer = jmsContext.createProducer();
已尝试异常时编程重建ConnectionFactory,问题未解决。
补充现象
- 数据库断连时,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)
- 停止服务时偶现线程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侧配置与生命周期管控
- 调整临界错误处理策略,避免JDBC临时断连直接触发Broker关停。在EmbeddedActiveMQ的配置中添加以下参数,将临界错误响应改为记录日志而非关停服务:
同时JDBC层使用带连接检测、自动重连的连接池(如HikariCP),配置连接测试查询、合理的连接超时和重试间隔,优先在JDBC层消化临时连接中断异常,避免异常透传给Artemis临界分析器。<critical-analyzer-policy>LOG</critical-analyzer-policy> <critical-analyzer-check-period>5000</critical-analyzer-check-period> <critical-analyzer-timeout>30000</critical-analyzer-timeout> - 实现Broker安全重启逻辑。增加Broker状态定时检测任务,当检测到Broker异常停止、且数据库连接恢复正常时,严格按照「先执行完整stop流程→等待所有服务线程终止、文件锁释放→再执行start」的流程拉起Broker,禁止在Broker未完成清理时直接调用start。
- 修复文件锁阻塞问题,配置文件锁超时时间:
锁等待超时后强制释放残留锁,避免线程无限阻塞。<file-lock-timeout>5000</file-lock-timeout>
客户端侧调整
- 废弃JMSContext、MessageProducer的单例初始化逻辑。每次执行消息收发操作前检测会话状态,捕获到
Session is closed/Consumer is closed异常时,直接销毁旧实例,重新从ConnectionFactory创建新的JMSContext、Producer/Consumer实例后重试操作。 - 为InVM连接配置客户端重试参数,修改ConnectionFactory配置,添加以下属性:
让客户端在Broker重启窗口期自动重试连接,减少临时异常抛出。<property name="retryInterval" value="1000"/> <property name="retryAttempts" value="10"/> <property name="failoverOnInitialConnection" value="false"/> <property name="clientFailureCheckPeriod" value="2000"/>
验证效果
按照原有复现流程操作:关停PostgreSQL时消息收发返回临时失败,数据库恢复、Broker正常拉起后,客户端重建会话即可正常执行消息收发,无Session is closed异常;服务停止时不会出现文件锁阻塞问题。
内容的提问来源于stack exchange,提问作者Vishal
相关产品推荐
相关产品推荐

