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

Spring Boot中SQS JMS消息失败后未重试的问题排查

问题描述

我在Spring Boot项目中用JMS对接AWS SQS,现有配置和接收器代码如下:

SQS/JMS配置代码

private final SQSConnectionFactory sqsConnectionFactory = new SQSConnectionFactory(
 new ProviderConfiguration().withNumberOfMessagesToPrefetch(10),
 AmazonSQSClientBuilder.defaultClient());

@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
 DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
 factory.setConnectionFactory(this.sqsConnectionFactory);
 factory.setDestinationResolver(new DynamicDestinationResolver());
 factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
 return factory;
}

消息接收器代码

@Service
public class HandleMessage {
 @Transactional
 @JmsListener(destination = "${sqs.handler}")
 public void receive(String message) throws IOException, JMSException {
     // 业务处理逻辑
     if (message.contains("test")) throw new JMSException("boom!");
     // 其他处理
 }
}

现在遇到的问题是:所有消息都被处理,包含"test"的消息抛出异常后直接消失,完全没触发重试。想请教是否需要修改SQS配置?另外@Transactional注解可能非必需,我的需求是Spring Boot在出现异常时通知SQS消息处理失败,让消息能自动重试。当前SQS的属性如下:

  • 最大消息大小:256 KB
  • 消息保留周期:4天
  • 默认可见性超时:30秒
  • 传递延迟:0秒
  • 接收消息等待时间:0秒
  • 基于内容的去重:未启用
问题分析

出现这个问题的核心原因是**@Transactional注解干扰了SQS消息的确认逻辑**,再结合当前的JMS会话确认模式设置,导致异常抛出后消息被错误地确认并删除:

  1. @Transactional的影响:给JMS监听方法加@Transactional后,Spring会把JMS会话绑定到Spring事务上下文。一旦方法抛出异常,Spring会触发事务回滚,但AWS SQS的JMS客户端对事务的处理和传统JMS不同——回滚操作并不会让消息重新回到队列,反而可能直接标记为已处理。
  2. CLIENT_ACKNOWLEDGE模式的误区:当前配置的Session.CLIENT_ACKNOWLEDGE模式下,正常情况Spring会在方法成功执行后自动确认消息,但结合@Transactional后,事务回滚逻辑会覆盖默认的异常处理逻辑,导致消息被意外确认。

另外你当前的SQS基础配置(比如30秒可见性超时、4天保留周期)是合理的,不需要修改这些属性,核心问题在Spring的JMS配置和代码逻辑上。

解决方案

按照以下步骤调整,就能实现异常时通知SQS重试消息:

1. 移除@Transactional注解

既然你提到这个注解非必需,直接去掉它是关键。这样Spring的JMS listener容器会按照默认的异常处理逻辑来处理消息确认:

@Service
public class HandleMessage {
 // 移除@Transactional
 @JmsListener(destination = "${sqs.handler}")
 public void receive(String message) throws IOException, JMSException {
     // 业务处理逻辑
     if (message.contains("test")) throw new JMSException("boom!");
     // 其他处理
 }
}

2. 调整JMS容器的会话确认模式(可选但推荐)

将会话确认模式改为Session.SESSION_TRANSACTED,让Spring通过事务提交/回滚来控制消息的确认:

@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
 DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
 factory.setConnectionFactory(this.sqsConnectionFactory);
 factory.setDestinationResolver(new DynamicDestinationResolver());
 // 改为SESSION_TRANSACTED模式
 factory.setSessionAcknowledgeMode(Session.SESSION_TRANSACTED);
 return factory;
}

这种模式下,方法成功执行时Spring会提交事务,SQS会标记消息为已处理;方法抛出异常时事务回滚,消息会在可见性超时(30秒)后重新回到队列,触发重试。

3. 配置重试次数与死信队列(可选)

如果需要限制重试次数,避免消息无限循环,可以给SQS配置死信队列(DLQ):

  • 创建一个死信队列,作为异常消息的最终存储地
  • 在原队列的红rive策略中设置maxReceiveCount(比如5次),当消息被重试超过5次后,自动转移到死信队列

这样既保证了异常消息的重试机会,又不会让无效消息一直占用队列资源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 07:47:29