Resilience4J Retry 的预期行为是什么?

Fer*_*sen 5 java spring spring-boot resilience4j resilience4j-retry

我在 Spring Boot 项目中使用 Resilience4J 来调用 REST 客户端,如下所示:

@Retry(name = "customerService")
public Customer getCustomer(String customerNumber) {
    restTemplate.exchange("https://customer-service.net", HttpMethod.GET, ..., customerNumber);
}
Run Code Online (Sandbox Code Playgroud)

使用此配置:

resilience4j.retry:
    instances:
        customerService:
            maxAttempts: 3
            waitDuration: 10s
            retryExceptions:
                - org.springframework.web.client.HttpServerErrorException
Run Code Online (Sandbox Code Playgroud)

我的期望是,如果restTemplate.exchange()调用 且客户服务以 a 响应HttpServerErrorException,则该getCustomer()方法将在等待 10 秒后再调用 3 次。

然而,这种情况并非如此。

该方法不会再被调用,并且会立即抛出异常。

看到示例中包含后备方法,我决定添加它,即使我真的不想调用不同的方法,我只想再次调用我的原始方法。

无论如何,我指定了一个回退:

@Retry(name = "customerService", fallback = "customerFb")
public Customer getCustomer(String customerNumber) {
    return getCustomer();
}

private Customer customerFb(String customerNumber, HttpServerErrorException ex) {
    log.error("Could not retrieve customer... retrying...");
    return getCustomer();
}

private Customer getCustomer(String customerNumber) {
    return restTemplate.exchange("https://customer-service.net", HttpMethod.GET, ..., customerNumber);
}
Run Code Online (Sandbox Code Playgroud)

现在,我看到回退方法正在重试,但是,每次都会抛出 HttpServerErrorException,这意味着消费者将收到异常作为对其调用的响应。

我的问题是:

是否需要实施后备方法才能使重试功能发挥作用?

抛出异常是预期的行为吗?难道我做错了什么?我不希望此服务的调用者在所有重试尝试完成之前收到异常。

谢谢

Aru*_*ala 13

问:是否需要实施后备方法才能使重试功能发挥作用?

答:不,Resilience4J 重试功能中的回退可选的。

行为Resilience4J Retry

  1. 启动时,弹性重试会从 application.properties/yml 加载配置(如果已配置),否则将使用文档中提到的默认值进行初始化。

  2. 当调用带有@Retry注解的方法时,该方法将处于重试监控之下。

  3. 如果显式配置了属性resilience4j.retry.instances.<instance name>.retryExceptions,则只有配置的异常才会被视为失败,并且只有这些失败才会触发重试,而对于其余异常,在没有重试功能的情况下,它会表现正常。

  4. 当带注释的方法下发生预期异常时@retry,它不会记录有关该异常的任何内容,但会根据maxAttempts配置的属性重试相同的方法。maxAttempts属性的默认值为3。超过 maxAttempts 后,它会抛出异常并可以在日志中看到。

  5. 还有一些属性,如waitDurationintervalFunctionignoreExceptions.. e.tc 可以显式配置。有关更多信息,请查看文档链接。

  6. 要查看用 注释的方法中异常事件期间实际发生的情况@retry,请启用 RetryRegistry 事件使用者来打印收到的事件。

RetryRegistry 事件监听器的示例代码:

package com.resilience.retry.config;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import io.github.resilience4j.retry.RetryRegistry;
import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
public class RetryRegistryEventListener {

    @Autowired
    private RetryRegistry registry;


    @PostConstruct
    public void postConstruct() {
        //registry.retry(<resilience retry instance name>)
        registry.retry("sample-api").getEventPublisher()
                .onRetry(ev -> log.info("#### RetryRegistryEventListener message: {}", ev));
    }
}
Run Code Online (Sandbox Code Playgroud)

示例日志:

2021-11-01 14:55:12.337  INFO 18176 --- [nio-8080-exec-1] c.r.retry.controller.RetryController     : Sample Api call receieved
2021-11-01 14:55:12.345  INFO 18176 --- [nio-8080-exec-1] c.r.r.config.RetryRegistryEventListener  : #### RetryRegistryEventListener message: 2021-11-01T14:55:12.344325600+05:30[Asia/Calcutta]: Retry 'sample-api', waiting PT10S until attempt '1'. Last attempt failed with exception 'org.springframework.web.client.HttpServerErrorException: 500 INTERNAL_SERVER_ERROR'.
2021-11-01 14:55:12.350  INFO 18176 --- [nio-8080-exec-1] c.r.retry.controller.RetryController     : messsage: 2021-11-01T14:55:12.344325600+05:30[Asia/Calcutta]: Retry 'sample-api', waiting PT10S until attempt '1'. Last attempt failed with exception 'org.springframework.web.client.HttpServerErrorException: 500 INTERNAL_SERVER_ERROR'.
2021-11-01 14:55:22.359  INFO 18176 --- [nio-8080-exec-1] c.r.retry.controller.RetryController     : Sample Api call receieved
2021-11-01 14:55:22.360  INFO 18176 --- [nio-8080-exec-1] c.r.r.config.RetryRegistryEventListener  : #### RetryRegistryEventListener message: 2021-11-01T14:55:22.360672900+05:30[Asia/Calcutta]: Retry 'sample-api', waiting PT10S until attempt '2'. Last attempt failed with exception 'org.springframework.web.client.HttpServerErrorException: 500 INTERNAL_SERVER_ERROR'.
2021-11-01 14:55:22.361  INFO 18176 --- [nio-8080-exec-1] c.r.retry.controller.RetryController     : messsage: 2021-11-01T14:55:22.360672900+05:30[Asia/Calcutta]: Retry 'sample-api', waiting PT10S until attempt '2'. Last attempt failed with exception 'org.springframework.web.client.HttpServerErrorException: 500 INTERNAL_SERVER_ERROR'.
Run Code Online (Sandbox Code Playgroud)

@FerdTurgusen:我相信您的代码中存在一些错误,否则它会正常工作。根据问题中给出的信息,我无法准确找到问题。因此,我创建了一个带有resilience4j示例的Spring Boot示例,复制了你的问题,它对我来说工作得很好,因此上传到Github供你参考。我建议您添加 RetryRegistryEventListener 类并在事件日志中查找问题,如果仍未解决,请分享事件监听器日志。

Github 参考带有resilience4j重试项目的示例spring-boot