Search code examples
springresilience4j

Resilience4j + Spring instance of CircuitBreaker


I would like to use Resilience4j to deal with fault tolerance, I am using CircuitBreaker and TimerLimit.

I would like to separate business logic of fault tolerance behavior, to not "dirty" my business code.

So, I am thinking to use Command pattern to execute my methods that will be treat, like Hystrix do with HystrixCommand.

Example:

public class MyCommand {

    private static final CircuitBreaker circuitBreaker;
    private Long param1, param2;
    private MyService myService;
    private static final TimeLimiter timeLimiter;

    static {
        long ttl = 50000;
        TimeLimiterConfig configTimerLimit
                = TimeLimiterConfig.custom().timeoutDuration(Duration.ofMillis(ttl)).build();
        timeLimiter = TimeLimiter.of(configTimerLimit);
       
        // I got the configuration from a class that I created.
        circuitBreaker = CircuitBreaker.of("my", CircuitBreakerConfigOptions.defaultForExternalService());
    }

    public MyCommand(Long param1, Long param2, MyService myService) {
        this.param1 = param1;
        this.param2 = param2;
        this.myService = myService;
    }

    public String run() {
        Callable<String> stringCallable = TimeLimiter.decorateFutureSupplier(timeLimiter,
                () -> CompletableFuture.supplyAsync(() -> myService.hello(param1, param2)));

        Callable<String> callable = CircuitBreaker.decorateCallable(circuitBreaker, stringCallable);

        return Try.of(callable::call).recover(t -> fallback(t)).get();
    }

    protected String fallback(Throwable throwable) {
        Callable<String> stringCallable = TimeLimiter.decorateFutureSupplier(timeLimiter,
                () -> CompletableFuture.supplyAsync(() -> myService.otherHello(param1, param2)));

        return Try.of(stringCallable::call).getOrElse("Fallback");
    }
}

Calling in my Controller:

@ApiOperation(value = "Only to test")
@GetMapping(value = "/execute", produces = MediaType.APPLICATION_JSON)
public String execute() {
    return new MyCommand(1L, 2L, new MyService()).run();
}

My doubts:

1 - In this case, circuitBreaker really needs to be static, because I understood that the same object needs to be shared between the same method that you want to threat, I am right?

2 - How I have many instances of this application, circuitBreaker works individually for each instance? I am right?


Solution

  • Since it seems that you are using Spring Boot, you could use the resilience4j-spring-boot-2 starter module which also has support for annotations.

    https://resilience4j.readme.io/docs/getting-started-3