see: Java - Resilience4j

Code Example

1 - Declare Dependencies

dependencies pom.xml

<!-- Resilience4j -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
 
<!-- Reactive Resilience4j -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>
 
<!-- AOP is required for Resilience4j's @CircuitBreaker to work -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2 - Configure Resilience4j’s Circuit Breakers

two ways to configure Resilience4j’s CircuitBreakers:

  • programmatically
  • application.yml and let Spring auto-configure beans
Programmatically
import io.github.resilience4j.common.circuitbreaker.configuration.CircuitBreakerConfigCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.Duration;
import static io.github.resilience4j.circuitbreaker.CircuitBreakerConfig.SlidingWindowType.COUNT_BASED;
 
@Configuration
public class CircuitBreakerConfig {
 
    @Bean
    public CircuitBreakerConfigCustomizer someRemoteSvcCircitBreaker() {
        //https://resilience4j.readme.io/docs/circuitbreaker
        return CircuitBreakerConfigCustomizer
                .of("marcusServiceA", builder -> {
                    builder.slidingWindowSize(5);
                    builder.failureRateThreshold(3);
                    builder.waitDurationInOpenState(Duration.ofSeconds(10));
                    builder.slowCallDurationThreshold(Duration.ofSeconds(5));
                    builder.slowCallRateThreshold(100);
                    builder.permittedNumberOfCallsInHalfOpenState(2);
                    builder.slidingWindowType(COUNT_BASED);
                });
    }
}
Via application.yml & Spring Auto-Configuration
resilience4j.circuitbreaker:
  instances:
    marcusServiceA:
      registerHealthIndicator: true
      slidingWindowSize: 10
    marcusServiceB:
      registerHealthIndicator: true
      slidingWindowSize: 10
      permittedNumberOfCallsInHalfOpenState: 3
      slidingWindowType: TIME_BASED
      minimumNumberOfCalls: 20
      waitDurationInOpenState: 50s
      failureRateThreshold: 50
      eventConsumerBufferSize: 10
# see example code for more

3 - Using Configured Circuit Breakers

import io.github.resilience4j.bulkhead.annotation.Bulkhead;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import io.github.resilience4j.retry.annotation.Retry;
import io.github.resilience4j.timelimiter.annotation.TimeLimiter;
import org.springframework.stereotype.Service;
 
@Service
public class RemoteServiceClient {
 
    @CircuitBreaker(name = "marcusServiceA", fallbackMethod = "callFail")
    public String call() {
        System.out.println("RemoteServiceClient.call() - executed");
        throw new RuntimeException("error with remote service");
    }
 
    private String callFail(RuntimeException e) {
        System.out.println("RemoteServiceClient.callFail() - executed");
        return "remote call failed";
    }
}