我想在 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 错误。然后是重试,但这是即时重试。为什么会这样,如何使用指数退避策略正确配置它?它正在重试,但不是指数延迟时间。
代码ClientConfiguration
中设置的退避策略用于为 AWS 客户端重试连接到 AWS 服务提供延迟。这意味着,如果 AWS SQS 客户端(例如由于某种原因(无法连接到 AWS SQS 服务以获取消息(或轮询新消息(,则将使用您设置的策略。如果发生此类故障,则应在配置的ExponentialBackoffStrategy
提供的延迟之后进行下一次尝试。有关更多详细信息,请参阅此处的官方文档。
立即重试的原因
对于您的情况,底层客户端(由 Spring 的@JmsListener
使用(已经从 SQS 服务中获取了消息。这一步的失败会使用ExponentialBackoffStrategy
.在此之后发生故障(例如在 404 之后引发的异常(将触发对 SQS 服务的故障确认,并且该服务将使消息立即再次可见以供使用。
如何将退避策略与重新交付相关联
可悲的是,该策略不能与消息使用失败相关联。 所需的延迟实际上是 JMS 2.0 规范的重新交付延迟。但是您似乎正在使用的 SQS JMS 提供程序是这个 https://github.com/awslabs/amazon-sqs-java-messaging-lib,即 JMS 1.1 实现。以下是从他们的文档中引用的相同内容:
此项目基于适用于 Java 的 AWS 开发工具包构建,以使用 Amazon SQS 作为 JMS(如 1.1 规范中所定义(提供程序
此外,SQS 在其 redrive-policy 中没有类似redelivery-delay
的内容(只有Maximum Receives
和Dead Letter Queue
关联(。因此,一种可能的解决方法是自行处理故障,并在每次重新排队时以增量方式设置特定于消息的延迟(更多内容 此处((这可能包括处理标头中的重试计数,而不是使用 JMS(。请注意,这可能会产生额外费用。
附带说明:向队列添加延迟或可见性超时无助于读取消息时失败之间的延迟。