ActiveMQ故障重试次数有限时如何恢复JMS入站网关容器
问题结论
当退避策略达到最大尝试次数导致容器停止后,Spring JMS 没有提供开箱即用的自动恢复配置。你看到的Stopping container for destination 'senExtractWorkerInGateway': back-off policy does not allow for further attempts.日志,是消息监听容器在退避策略返回停止指令时打印的,此时容器生命周期状态标记为已停止,不会主动感知ActiveMQ服务状态并自行重启,需要通过配置调整或自定义逻辑实现恢复。
可行实现方案
方案1:调整退避策略为无限重试(最简便)
当前自定义CustomMessageListenerContainer使用的是有限尝试次数的退避策略,直接替换为无最大时长限制的退避策略即可,容器不会因为重试次数耗尽停止,会在Broker恢复后自动重连。
示例退避配置:
ExponentialBackOff infiniteRetryBackOff = new ExponentialBackOff(); infiniteRetryBackOff.setInitialInterval(1000); // 首次重试间隔1秒 infiniteRetryBackOff.setMultiplier(2); // 每次重试间隔翻倍 infiniteRetryBackOff.setMaxInterval(60000); // 最大重试间隔不超过1分钟 infiniteRetryBackOff.setMaxElapsedTime(-1); // 设为-1代表无限重试,不会触发容器停止 // 将退避策略设置到自定义容器中 customMessageListenerContainer.setBackOff(infiniteRetryBackOff);
方案2:保留有限次退避,自定义探测重启逻辑
如果业务上必须保留有限次退避的配置,可以在自定义容器中扩展停止后的逻辑,增加ActiveMQ可用性探测,服务恢复后自动重启容器。
示例自定义容器实现:
public class CustomMessageListenerContainer extends DefaultMessageListenerContainer { private final ConnectionFactory connectionFactory; private final ScheduledExecutorService detectScheduler = Executors.newSingleThreadScheduledExecutor(); public CustomMessageListenerContainer(ConnectionFactory connectionFactory) { this.connectionFactory = connectionFactory; } @Override protected void handleListenerSetupFailure(Throwable ex, boolean alreadyRecovered) { super.handleListenerSetupFailure(ex, alreadyRecovered); // 退避耗尽容器已停止时,启动服务探测任务 if (!isRunning()) { detectScheduler.scheduleWithFixedDelay(() -> { try (Connection testConn = connectionFactory.createConnection()){ testConn.start(); // 探测到连接可用,重启容器 start(); // 重启成功后关闭探测线程池 detectScheduler.shutdown(); } catch (JMSException e) { // 服务未恢复,等待下一轮探测 } }, 10, 30, TimeUnit.SECONDS); // 首次探测延迟10秒,后续每30秒探测一次 } } }
当前网关配置中container-class已经指定为自定义类,直接替换类实现即可,不需要修改XML网关配置。
注意事项
- 当前配置把
concurrent-consumers和max-concurrent-consumers都固定为25,ActiveMQ刚恢复时如果大量工作端同时建立25个连接,容易给正在恢复持久化数据的Broker造成瞬时压力,建议适当调小初始消费者数量,或给重连逻辑增加随机偏移延迟,避免连接风暴。 - 配置的
receive-timeout和reply-timeout为20分钟,注意和业务侧的超时时间匹配,避免消息处理超时导致的异常被误判为连接故障触发退避。
内容的提问来源于stack exchange,提问作者Krishna Kishore
相关产品推荐
相关产品推荐

