长时间无活动后JMS Appender会话报错问题咨询
遇到这种长时间无日志活动后抛出Session is closed的问题,其实是很常见的JMS客户端-服务端超时不匹配导致的,结合你的配置和JBoss EAP7的特性,咱们一步步来分析解决:
问题根源
虽然你配置了reconnectIntervalMill="60000",但JBoss EAP7的ActiveMQ Artemis默认会对闲置的会话设置超时回收(默认一般是30分钟)。当你的应用长时间没产生日志,服务端会主动关闭这个闲置会话,而Log4j2的默认JMS Appender可能没有及时检测到会话已失效,当再次发送日志时就会抛出这个异常。
具体解决方案
1. 检查并调整JBoss服务端的会话超时配置
首先登录JBoss服务器,打开standalone.xml(或domain.xml),找到消息子系统的配置段:
<subsystem xmlns="urn:jboss:domain:messaging-activemq:11.0"> <server name="default"> <!-- 找到session配置 --> <session session-timeout="1800"/> <!-- 默认是1800秒,即30分钟 --> ... </server> </subsystem>
如果你的应用可能会有更长时间的日志闲置,可以调大这个session-timeout值,比如设为3600(1小时)或者更大。注意修改后需要重启JBoss生效。
2. 优化Log4j2 JMS Appender的配置
你的现有配置已经开启了immediateFail="false",这是正确的,但可以补充几个参数增强重连能力:
<JMS name="HIFAuditAppender" destinationBindingName="jms/queue/HIFAuditQueue" factoryBindingName="jms/RemoteConnectionFactory" providerURL="http-remoting://hsnban-bil01.bannerlab.int:8080" username="hcmuser" password="gators123=" immediateFail="false" reconnectIntervalMill="60000" reconnectAttempts="10" <!-- 添加最大重连次数 --> lookupOnStartup="false" <!-- 每次发送前重新查找JMS资源,避免引用失效 --> factoryName="org.jboss.naming.remote.client.InitialContextFactory" />
reconnectAttempts:设置最大重连尝试次数,避免无限重连消耗资源lookupOnStartup="false":让Appender在每次发送日志前重新查找连接工厂和队列,避免长时间闲置后资源引用失效
3. 自定义JMS Appender实现主动重连
如果默认的重连逻辑还是无法覆盖场景,可以扩展Log4j2的JmsAppender,在捕获到Session is closed异常时主动重新初始化连接和会话:
import org.apache.logging.log4j.core.appender.AppenderLoggingException; import org.apache.logging.log4j.core.appender.jms.JmsAppender; import org.apache.logging.log4j.core.LogEvent; public class ReconnectableJmsAppender extends JmsAppender { @Override protected void send(final LogEvent event) { try { super.send(event); } catch (AppenderLoggingException e) { // 检查是否是Session closed异常 if (e.getCause() instanceof IllegalStateException && "Session is closed".equals(e.getCause().getMessage())) { // 停止并重新启动Appender,重建连接和会话 try { this.stop(); this.start(); // 重新发送日志事件 super.send(event); } catch (Exception reinitException) { throw new AppenderLoggingException("Failed to reinitialize JMS connection", reinitException); } } else { // 其他异常直接抛出 throw e; } } } }
然后在log4j2配置文件里使用这个自定义Appender(注意配置正确的类全路径):
<ReconnectableJms name="HIFAuditAppender" destinationBindingName="jms/queue/HIFAuditQueue" factoryBindingName="jms/RemoteConnectionFactory" providerURL="http-remoting://hsnban-bil01.bannerlab.int:8080" username="hcmuser" password="gators123=" immediateFail="false" reconnectIntervalMill="60000" factoryName="org.jboss.naming.remote.client.InitialContextFactory" />
4. 开启调试日志排查重连细节
如果还是不确定问题出在哪,可以开启Log4j2对JMS Appender的调试日志,查看重连过程:
<Logger name="org.apache.logging.log4j.core.appender.jms" level="DEBUG" additivity="false"> <AppenderRef ref="你的控制台或文件Appender"/> </Logger>
这样就能看到Appender在异常发生后是否触发了重连,以及重连过程中有没有其他错误,方便定位问题。
总结
核心思路是让客户端的重连机制和服务端的会话超时策略匹配,要么调大服务端的会话超时时间,要么增强客户端的重连逻辑,必要时通过自定义Appender主动处理会话失效的场景。
内容的提问来源于stack exchange,提问作者OldProgrammer

