[英]SQS JMS Message not being retried on a failure in spring boot
给定这样的 JMS/SQS 配置:
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!");
...
}
我发现所有消息都在处理中,并且包含测试的消息消失了,而不是重试。 SQS 配置中是否可能需要更改某些内容。
@Transactional
属性可能需要也可能不需要,但我想要的是 Spring Boot 在出现异常时向 SQS 发出信号失败,我确信这是可能的。
Maximum message size 256 KB
Last updated 5/25/2020, 12:00:10
Message retention period 4 Days
Default visibility timeout 30 Seconds
Messages available 0
Delivery delay 0 Seconds
Messages in flight (not available to other consumers) 0
Receive message wait time 0 Seconds
Messages delayed 0
Content-based deduplication -
我希望这能回答你的问题,或者至少让你朝着正确的方向前进。
您需要将 JTA 事务管理器部署为 Spring PlatformTransactionManager。 有很多可用的,我用 Arjuna 取得了很好的效果。 添加启动器:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-narayana</artifactId>
</dependency>
将部署 Arjuna 并将其配置为 PlatformTransactionManager。
有用的日志:
<logger name="com.arjuna" level="TRACE" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
删除:
factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
并添加:
factory.setSessionTransacted(true);
当消息侦听器容器开始侦听消息时,它应该创建一个事务上下文。 当您使用事务方法时,该方法应该加入事务上下文。 如果该方法的提交成功,那么您应该在 Arjuna 日志记录中看到消息 receive get commit 。 如果出现异常,则侦听器事务将回滚,并且您的消息将返回到您的队列。
只是为了搅浑水……您只有一种事务性资源 - JMS 会话。 您可以避免使用完整的 JTA 事务管理器。 我个人不认为它们过度占用资源。 您可以创建一个 JmsTransactionManager,并将您的连接工厂传递给它。 然后,您可以将消息侦听器容器工厂上的 JmsTransactionManager 设置为事务管理器。
我居然解决了这个问题,很尴尬。
不过,我真的很喜欢上述答案中的所有建议,并已将其标记为正确,因为在某些情况下参加交易会带来巨大的好处。
但是对于那些可能偶然发现这个问题的人来说,一个温和的提醒,以确保地球上的某个地方(在我的情况下是不同的大陆)没有其他服务器正在消耗失败的消息。
一旦我确定我是这个星球上唯一一台监听消息的机器,我就得到了我期望收到的所有重试。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.