Spring Boot失败时不会重试SQS JMS消息

问题描述

给出这样的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设置为事务管理器。

,

我实际上解决了这个问题,这很令人尴尬。
我真的很喜欢上述答案中的所有建议,并已将其标记为正确,因为在某些情况下加入交易将带来巨大好处。

但是对于那些可能会偶然发现此问题的人,谨在此提醒您,以确保星球上某处(在我的情况下为另一大洲)没有其他服务器在消耗该服务器。失败的消息。

一旦我确定自己是地球上唯一一个收听消息的机器,便得到了所有希望得到的重试。