当前位置: 首页 > 知识库问答 >
问题:

Failsafe with RetryPolicy和CircuitBreaker引发

童花蜂
2023-03-14

我正在尝试将重试策略与具有Failsafe的CircuitBreaker模式结合起来,但当尝试时电路开路并中断时,会出现CircuitBreakerOpenException异常。

https://github.com/jhalterman/failsafe

问题的产生是因为重试的延迟时间小于电路的关闭时间。

如何控制此异常,使重试策略不中断?我之所以要这样做,是因为我可以让多个同时启动的实例向rest服务发出请求,并且重试不会中断。

我的代码:

public class UnstableApplication {
    private final int MAX_FAILS = 4;
    private AtomicInteger failCount = new AtomicInteger(1);

    public String generateId() throws Exception {
        if (failCount.getAndIncrement() < MAX_FAILS) {
            System.err.printf("UnstableApplication throws SampleException at '%s'\n", ZonedDateTime.now());
            throw new Exception();
        }

        final String id = UUID.randomUUID().toString();
        System.out.printf("UnstableApplication: id '%s' generated at '%s'\n", id, ZonedDateTime.now());

        return id;
    }

}

public class FailsafeExample {

    public static void main(String[] args) throws Exception {

        UnstableApplication app = new UnstableApplication();

        RetryPolicy retryPolicy = new RetryPolicy()
                .retryOn(Exception.class)
                .withDelay(2, TimeUnit.SECONDS)
                .withMaxRetries(5);

        CircuitBreaker breaker = new CircuitBreaker();
        breaker.withFailureThreshold(2);
        breaker.withDelay(5, TimeUnit.SECONDS);
        breaker.withSuccessThreshold(3);
        breaker.onOpen(() -> {
            System.out.println("Circuit breaker is open");
        });

        breaker.onClose(() -> {
            System.out.println("Circuit breaker is close");
        });

        breaker.onHalfOpen(() -> {
            System.out.println("Circuit breaker is half-close");
        }); 

        Failsafe.with(retryPolicy)
        .with(breaker)
        .onFailedAttempt((a, b) -> {
            System.out.println(
                    String.format("Failed with exception: %s, at %s, circuit-breaker state is: %s", 
                            b, ZonedDateTime.now(), breaker.getState()));
        })
        .onSuccess(cxn -> {
            System.out.println("Succcess!");
        })
        .onFailure(cxn -> {
            System.out.println("Failed!");
        })
        .get(new Callable<String>() {
            @Override
            public String call() throws Exception {
                return app.generateId();
            }
        });
    }
}

我的结果:

UnstableApplication throws SampleException at '2019-05-31T16:30:09.214Z[Etc/UTC]'
Failed with exception: java.lang.Exception, at 2019-05-31T16:30:09.221Z[Etc/UTC], circuit-breaker state is: CLOSED
UnstableApplication throws SampleException at '2019-05-31T16:30:11.229Z[Etc/UTC]'
Circuit breaker is open
Failed with exception: java.lang.Exception, at 2019-05-31T16:30:11.230Z[Etc/UTC], circuit-breaker state is: OPEN
Exception in thread "main" net.jodah.failsafe.CircuitBreakerOpenException
    at net.jodah.failsafe.SyncFailsafe.call(SyncFailsafe.java:136)
    at net.jodah.failsafe.SyncFailsafe.get(SyncFailsafe.java:56)
    at com.kash.test.Foo.main(Foo.java:63)

共有2个答案

朱欣荣
2023-03-14

这是有意为之的行为。当电路打开时,对该端点的请求将被停止--如果依赖关系被破坏或不可靠,当然您的重试也必须被切断,否则您将经历重试的堆积如山,就像您根本没有cb一样容易。

如果您想继续发送请求,要么您的断路触发器太敏感,要么您处于不需要断路的情况下。failsafe执行的行为很可能是正确的方法。

如果您真的想这样做,请将您的重试逻辑放在您发送给电路断路器的函数中,而不是使用来自FailSafe的RetryPolicy。或者在重试策略中使用指数退避函数。

柯立果
2023-03-14

以下是我在此示例案例中尝试将断路器与重试策略相结合时的理解:

CircuitBreaker breaker = new CircuitBreaker()
                .withFailureThreshold(3, 10)
                .withSuccessThreshold(5)
                .failOn(Exception.class)
                .withDelay(30, TimeUnit.SECONDS);

RetryPolicy retryPolicy = new RetryPolicy()
                .retryOn(ConnectException.class)
                .withDelay(3, TimeUnit.SECONDS)
                .withMaxRetries(5);
  • 首先,它将重试5次,但由于断路器的阈值为3,因此在第3次“连续”重试时,它将断开并断开电路。
  • 因此,一旦打开,它很可能仍然“可能重试”,但由于电路已经打开,仍在时间延迟下重试将导致CircuitBreakerOpenException。
 类似资料:
  • 我遇到了一个@circuitbreaker没有重试的问题。 我有一个服务类(例如类UserService和方法名getUser),这个方法调用另一个spring bean(例如AppClient和execute),后者又调用远程服务(REST调用)。execute方法用spring的@circuitbreaker-retry注释。 我在rest控制器中公开了对服务方法(类UserService和方

  • 我试图在我的Spring Boot(使用Swagger)中构建一个简单的断路器。 但它给出了同样的错误,“无法解决”。

  • 现在编译器很高兴了,所以我可以添加注释: 程序编译,运行,但是注释被完全忽略。

  • 问题内容: 这实际上有什么区别? 这工作正常: 但以下操作无效: 这是为什么? 问题答案: 那是因为双引号被认为是标准的,而单引号却没有。这并不是真正针对JQuery,而是关于JSON标准。因此,无论使用JS工具包,您都应该期待相同的行为。 值可以是带双引号的字符串,也可以是数字,也可以是true或false或null,或者是对象或数组。这些结构可以嵌套。

  • CreateIndexes 根据struct中的tag来创建索引 CreateUniques 根据struct中的tag来创建唯一索引

  • 问题内容: 我很沮丧 我希望能够在数据库名称中插入单引号-例如O’Connor。 因此,当插入数据库时​​,我这样做: 然后,我将$ lname插入数据库。 在数据库中时,它显示为O 'Connor。 因此,如果要在Web应用程序中记住该姓氏,则必须使用: 这一切似乎都很好。但是,我有一个搜索功能,可以搜索姓氏并显示结果。当我搜索时,我必须搜索O 'Connor以获得任何结果。 您会发现,在搜索之