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

Azure Service Bus会话异常关闭未恢复,配置并发时问题凸显求解决

问题:Spring Boot集成Azure Service Bus并发监听会话无法自动恢复

在Spring Boot集成Microsoft Azure Service Bus时,配置JMS监听的concurrency参数后,出现监听会话突然关闭、连接无法自动恢复的情况,且无明确错误码,异常日志如下:

javax.jms.IllegalStateException: The Session is closed
    at org.apache.qpid.jms.JmsSession.checkClosed(JmsSession.java:1101) ~[qpid-jms-client-0.53.0.jar!/:na]
    at org.apache.qpid.jms.JmsSession.rollback(JmsSession.java:263) ~[qpid-jms-client-0.53.0.jar!/:na]
    at org.messaginghub.pooled.jms.JmsPoolSession.close(JmsPoolSession.java:112) ~[pooled-jms-1.2.4.jar!/:na]
    at org.springframework.jms.support.JmsUtils.closeSession(JmsUtils.java:109) ~[spring-jms-5.3.27.jar!/:5.3.27]
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.clearResources(DefaultMessageListenerContainer.java:1289) ~[spring-jms-5.3.27.jar!/:5.3.27]
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1135) ~[spring-jms-5.3.27.jar!/:5.3.27]
    at java.base/java.lang.Thread.run(Unknown Source) ~[na:na]

2023-10-03 21:41:40.521  WARN 1 --- [ontainer#0-4019] o.s.j.l.DefaultMessageListenerContainer  : Setup of JMS message listener invoker failed for destination 'carton-status-update' - trying to recover. Cause: The MessageConsumer is closed
2023-10-03 21:41:40.525  WARN 1 --- [ontainer#0-4019] o.m.pooled.jms.JmsPoolSession            : Caught exception trying rollback() when putting session back into the pool, will invalidate. javax.jms.IllegalStateException: The Session is closed

javax.jms.IllegalStateException: The Session is closed
    at org.apache.qpid.jms.JmsSession.checkClosed(JmsSession.java:1101) ~[qpid-jms-client-0.53.0.jar!/:na]
    at org.apache.qpid.jms.JmsSession.rollback(JmsSession.java:263) ~[qpid-jms-client-0.53.0.jar!/:na]
    at org.messaginghub.pooled.jms.JmsPoolSession.close(JmsPoolSession.java:112) ~[pooled-jms-1.2.4.jar!/:na]
    at org.messaginghub.pooled.jms.JmsPoolConnection.cleanupAllLoanedSessions(JmsPoolConnection.java:269) ~[pooled-jms-1.2.4.jar!/:na]
    at org.messaginghub.pooled.jms.JmsPoolConnection.close(JmsPoolConnection.java:80) ~[pooled-jms-1.2.4.jar!/:na]
    at org.springframework.jms.connection.ConnectionFactoryUtils.releaseConnection(ConnectionFactoryUtils.java:81) ~[spring-jms-5.3.27.jar!/:5.3.27]
    at org.springframework.jms.listener.AbstractJmsListeningContainer.refreshSharedConnection(AbstractJmsListeningContainer.java:394) ~[spring-jms-5.3.27.jar!/:5.3.27]
    at org.springframework.jms.listener.DefaultMessageListenerContainer.refreshConnectionUntilSuccessful(DefaultMessageListenerContainer.java:985) ~[spring-jms-5.3.27.jar!/:5.3.27]
    at org.springframework.jms.listener.DefaultMessageListenerContainer.recoverAfterListenerSetupFailure(DefaultMessageListenerContainer.java:959) ~[spring-jms-5.3.27.jar!/:5.3.27]
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1146) ~[spring-jms-5.3.27.jar!/:5.3.27]
    at java.base/java.lang.Thread.run(Unknown Source) ~[na:na] 

当前使用的JMS监听注解配置:

@JmsListener(destination = TOPIC_NAME, containerFactory = "topicJmsListenerContainerFactory", subscription = SUBSCRIPTION_NAME, concurrency="15-20")

解决方案

1. 调整连接池配置,避免会话回收时的rollback异常

配置JmsPoolConnectionFactory时,关闭会话归还时的自动rollback操作,防止因已关闭会话触发异常导致连接池失效:

@Bean
public JmsPoolConnectionFactory pooledConnectionFactory(AzureServiceBusJmsConnectionFactory azureConnectionFactory) {
    JmsPoolConnectionFactory pool = new JmsPoolConnectionFactory();
    pool.setConnectionFactory(azureConnectionFactory);
    pool.setRollbackOnReturn(false); // 核心配置:禁用归还会话时的rollback
    pool.setMaxConnections(20); // 匹配并发上限
    pool.setMaxSessionsPerConnection(1); // 每个连接绑定一个会话,避免会话池交叉影响
    return pool;
}

2. 配置监听器容器的主动恢复策略

针对DefaultJmsListenerContainerFactory,显式设置恢复间隔和缓存策略,确保异常后能快速重建会话:

@Bean
public DefaultJmsListenerContainerFactory topicJmsListenerContainerFactory(JmsPoolConnectionFactory pooledConnectionFactory) {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    factory.setConnectionFactory(pooledConnectionFactory);
    factory.setConcurrency("15-20");
    factory.setRecoveryInterval(5000); // 异常后每5秒尝试恢复连接
    factory.setCacheLevel(DefaultMessageListenerContainer.CACHE_CONSUMER); // 缓存消费者,减少重建开销
    factory.setSessionTransacted(false); // 无需事务时关闭,避免不必要的rollback操作
    return factory;
}

3. 增强Azure Service Bus客户端的连接稳定性

在配置文件中添加客户端心跳和超时配置,提前检测并回收无效连接:

spring:
  jms:
    servicebus:
      connection-string: ${AZURE_SERVICEBUS_CONNECTION_STRING}
      idle-timeout: 300000 # 5分钟空闲超时,自动回收闲置连接
      client-id: ${spring.application.name} # 标识客户端,便于Azure端排查

4. 自定义异常处理,主动触发连接刷新

实现JmsListenerErrorHandler,当检测到会话关闭异常时,主动触发监听器容器的连接刷新:

@Component
public class CustomJmsErrorHandler implements JmsListenerErrorHandler {
    @Autowired
    private ApplicationContext context;

    @Override
    public Object handleError(Message message, ListenerExecutionFailedException exception) throws Exception {
        // 识别会话关闭异常,主动刷新连接
        if (exception.getCause() instanceof IllegalStateException && 
            exception.getCause().getMessage().contains("The Session is closed")) {
            DefaultMessageListenerContainer container = context.getBean(DefaultMessageListenerContainer.class);
            container.refreshConnectionUntilSuccessful();
        }
        throw exception;
    }
}

在监听注解中绑定自定义错误处理器:

@JmsListener(destination = TOPIC_NAME, containerFactory = "topicJmsListenerContainerFactory", 
             subscription = SUBSCRIPTION_NAME, concurrency="15-20", errorHandler = "customJmsErrorHandler")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 10:25:53