0

我想在 Spring 应用程序中为 sqs 设置退避策略。我所做的是:

    @Bean
    public ConnectionFactory sqsConnectionFactory() {

        PredefinedBackoffStrategies.ExponentialBackoffStrategy backoffStrategy = new PredefinedBackoffStrategies.ExponentialBackoffStrategy(3, 27);
        RetryPolicy retryPolicy = new RetryPolicy(PredefinedRetryPolicies.DEFAULT_RETRY_CONDITION, backoffStrategy, PredefinedRetryPolicies.DEFAULT_MAX_ERROR_RETRY, false);
        return SQSConnectionFactory.builder()
                .withRegion(Region.getRegion(Regions.fromName(region)))
                .withAWSCredentialsProvider(new DefaultAWSCredentialsProviderChain())
                .withClientConfiguration(new ClientConfiguration().withRetryPolicy(retryPolicy))
                .build();
    }

,但没有效果。@JmsListener我通过简单的方法从 SQS 队列中读取。在此方法中调用其他 api。这个 api 返回我 404 错误。然后是重试,但它是即时重试。为什么会这样,如何使用指数退避策略正确配置它?它正在重试,但没有指数延迟时间。

4

1 回答 1

3

在您的代码中设置的退避策略ClientConfiguration用于为 AWS 客户端重试连接到 AWS 服务提供延迟。这意味着如果(例如由于某种原因)AWS SQS 客户端无法连接到 AWS SQS 服务以获取消息(或轮询新消息),则将使用您设置的策略。如果发生此类故障,则应在配置提供的延迟后进行下一次尝试ExponentialBackoffStrategy。有关详细信息,请参阅此处的官方文档

立即重试的原因

对于您的情况,消息已经由底层客户端(由 Spring 使用@JmsListener)从 SQS 服务中获取。这一步的失败将使用ExponentialBackoffStrategy. 之后的失败(如 404 之后抛出的异常)将触发对 SQS 服务的失败确认,并且该服务将使消息立即再次可见以供使用。

如何将退避策略与重新交付相关联

遗憾的是,该策略无法与消息消费失败相关联。所需的延迟实际上是 JMS 2.0 规范的redelivery-delay。但是您似乎正在使用的 SQS JMS 提供程序是https://github.com/awslabs/amazon-sqs-java-messaging-lib,它是 JMS 1.1 实现。以下是从他们的文档中引用的相同内容:

此项目构建在 AWS SDK for Java 之上,以使用 Amazon SQS 作为 JMS(如 1.1 规范中定义)提供程序

redelivery-delay此外,SQS在他们的 redrive-policy中没有任何类似的东西(只有Maximum ReceivesandDead Letter Queue关联)。因此,一种可能的解决方法是自行处理故障,并在每次重新排队时逐步设置特定于消息的延迟(此处更多)(这可能包括处理标头中的重试计数,而不是使用 JMS)。请注意,这可能会产生额外费用。

附带说明:向队列添加延迟或可见性超时将无助于读取消息时的故障之间的延迟。

于 2018-11-13T14:20:54.637 回答