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

服务器重启时JMS正在处理消息丢失问题求助

解决Spring JMS重启时消息丢失问题,实现可靠的消息确认

首先,你遇到的核心问题是消息确认时机不对——默认的自动确认模式会在消息被消费者接收后就从队列移除,一旦服务器在处理过程中宕机,未完成的消息就永久丢失了。下面给你两种可靠的解决方案,结合你的代码来调整:


方案1:使用会话事务(推荐,无需手动确认)

这种方式下,Spring容器会帮你管理事务:方法正常执行完就提交事务,消息从队列移除;如果方法抛出异常,事务回滚,消息自动放回队列,服务器重启后会重新消费。

完整的容器工厂配置

把你的responseMessageFactory Bean补充完整:

@Bean
public JmsListenerContainerFactory<DefaultMessageListenerContainer> responseMessageFactory() {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory());
    // 开启会话事务,核心配置
    factory.setSessionTransacted(true);
    // 可选:设置并发消费者数量,根据业务需求调整
    factory.setConcurrentConsumers(2);
    factory.setMaxConcurrentConsumers(5);
    // 可选:停止时拒绝接收新消息,避免重启前接收未处理的消息
    factory.setAcceptMessagesWhileStopping(false);
    return factory;
}

消息监听器写法

不需要手动调用确认方法,只要业务逻辑正常执行,事务自动提交:

@JmsListener(destination = "your-target-queue", containerFactory = "responseMessageFactory")
public void processResponseMessage(YourMessagePayload message) {
    // 这里写你的业务处理逻辑
    doBusinessLogic(message);
    
    // 不需要手动ack,方法正常结束=事务提交=消息被确认移除
}

如果处理中抛出异常,事务会自动回滚,消息会回到队列,重启后重新被消费。


方案2:手动确认模式(灵活控制确认时机)

如果需要更精细地控制确认时机(比如业务处理到某一步再确认),可以用CLIENT_ACKNOWLEDGE模式,手动调用消息的acknowledge()方法。

容器工厂配置

修改确认模式:

@Bean
public JmsListenerContainerFactory<DefaultMessageListenerContainer> responseMessageFactory() {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory());
    // 设置手动确认模式
    factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
    // 可选:关闭自动确认的兜底,确保只有手动ack才会移除消息
    factory.setAutoStartup(true);
    return factory;
}

消息监听器写法

需要注入Message对象,在业务处理完成后手动确认:

@JmsListener(destination = "your-target-queue", containerFactory = "responseMessageFactory")
public void processResponseMessage(YourMessagePayload message, Message jmsMessage) throws JMSException {
    try {
        // 执行业务逻辑
        doBusinessLogic(message);
        // 业务处理成功后,手动确认消息
        jmsMessage.acknowledge();
    } catch (Exception e) {
        // 处理失败时,调用recover()让消息重新回到队列
        ((SessionAwareMessageListener<?>) jmsMessage).getSession().recover();
        throw new RuntimeException("消息处理失败,已放回队列", e);
    }
}

关键注意事项

  • 死信队列配置:如果消息多次重试失败(比如业务逻辑一直报错),建议配置死信队列,避免消息无限循环占用资源。
  • ConnectionFactory事务支持:确保你的connectionFactory()返回的实例支持事务(比如ActiveMQ的ActiveMQConnectionFactory默认支持)。
  • 并发消费者:根据服务器CPU和内存情况调整concurrentConsumers和maxConcurrentConsumers,避免资源耗尽。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:34:08