首页 > 解决方案 > lambda 函数中的 Spring Retry 似乎不起作用

问题描述

我有一个用 Spring Boot 构建的 lambda 函数,它对每秒可以接受 10 个请求的服务进行 REST 调用。在这 10 个请求之后,我得到了 403。

事实证明,试图让一种方法在这种约束下工作是很困难的。

目前我的代码看起来像

@Slf4j
@UtilityClass
public class HttpUtil {

    private final RestTemplate restTemplate = new RestTemplate();

    @Retryable(maxAttempts = 60, backoff = @Backoff(delay = 10000, multiplier = 2))
    public ResponseEntity<String> sendPostRequest(@NonNull final MultiValueMap<String, Object> data, @NonNull final String url) {
        final HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(data, new HttpHeaders());

        return restTemplate.postForEntity(url, request, String.class);
    }
}

但是,如果我启动它并检查日志,我可以看到 403 异常被一遍又一遍地抛出,并且似乎没有发生“退避”期。

我试图扩展RetryListenerSupport以添加更多日志记录,以便我可以看到实际的回退期,但这似乎已被忽略,尽管已加载。这是否需要与 RetryTemplate` 一起使用而不仅仅是注释?

否则我的注释明显有问题吗?还是有一种更简单的方法可以在我的方法上实现“每秒 10 个请求的上限”?

编辑:

配置类

@EnableRetry
@Configuration
public class RetryTemplateConfig {

    @Bean
    public RetryTemplate retryTemplate() {
        final RetryTemplate retryTemplate = new RetryTemplate();
        retryTemplate.registerListener(new DefaultListenerSupport());
        return retryTemplate;
    }
}

和一个非常简单的听众

@Slf4j
public class DefaultListenerSupport extends RetryListenerSupport {

    @Override
    public <T, E extends Throwable> void close(final RetryContext context,
                                               final RetryCallback<T, E> callback, final Throwable throwable) {

        log.info("onClose {}", throwable.getMessage());

        super.close(context, callback, throwable);
    }

    @Override
    public <T, E extends Throwable> void onError(final RetryContext context,
                                                 final RetryCallback<T, E> callback, final Throwable throwable) {

        log.info("onError {}", throwable.getMessage());

        super.onError(context, callback, throwable);
    }

    @Override
    public <T, E extends Throwable> boolean open(final RetryContext context,
                                                 final RetryCallback<T, E> callback) {

        log.info("onOpen");

        return super.open(context, callback);
    }
}

干杯

标签: javaspring-bootspring-retry

解决方案


使用@Retryable注解的类需要是 Spring bean,否则您将需要RetryTemplate直接使用而不是注解。

如果你不希望你的类成为一个 bean,你可以这样做:

private static final RetryTemplate retryTemplate = new RetryTemplate();
    static {
         SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
         retryPolicy.setMaxAttempts(60);
         ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
         backOffPolicy.setMultiplier(2);
         backOffPolicy.setInitialInterval(10000);
         retryTemplate.setRetryPolicy(retryPolicy);
         retryTemplate.setBackOffPolicy(backOffPolicy);
    }
    private void doSomething() {
        retryTemplate.execute(retryContext -> {
            return restTemplate.postForEntity(url, request, String.class);
        });
    }

推荐阅读