Shop Resource          
Resilience4J Circuit Breaker
Created on Dec 2019

This article demonstrates on how to implement circuit breaker using Resilience4J. Circuit Breaker is a design pattern used to provide client resiliency. Client resiliency protects client that uses a remote service from failure when there is an exception thrown from the remote service, and propagates to client side. Circuit breaker prevents client keeps invoke on failure service.


Resilience4J Circuit breaker provides resiliency by decorating the invoke source using a functional programming style. Invoke source is one or more code statements that invoke the remote service. Circuit breaker pattern also consists of three states: CLOSE, OPEN, and HALF-OPEN.


(1) In CLOSE state, circuit breaker allows invoke-source to invoke the remote service.


(2) During CLOSE state, circuit breaker records the statistic of success and failure rate of invoke. If statistic shows that there are too many failures in invoke, or response is too slow from the remote service, the circuit breaker will transit to OPEN state.


(3) In OPEN state, circuit breaker blocks the execution of invoking source, and throws CallNotPermittedException.


(4) After a timed duration has elapsed, circuit breaker transits to HALF-OPEN state. At this state, circuit breaker restricts the number of executions of invoking source.


(5) Similar to CLOSE state, circuit breaker records the statistic of success and failure of invoking during HALF-OPEN state. If statistic shows that there are too many failures in invoke, or response is too slow from the remote service, the circuit breaker will transit back to OPEN state. Else, circuit breaker transits back to CLOSE state.


Circuit Breaker Configuration

The application requires to configure some parameter before the circuit breaker can be used. This configuration is provided in Spring configuration class. In this article, MicroserviceConfig.java is the Java class for that purpose:

@Configuration
public class MicroserviceConfig {
   
@Bean("DataServiceCb")
   
public CircuitBreaker circuitBreaker() {
       
CircuitBreakerConfig circuitBreakerConfig =
            CircuitBreakerConfig.custom
()
               
.slidingWindowSize(4)
               
.minimumNumberOfCalls(2)
               
.slidingWindowType(SlidingWindowType.COUNT_BASED)
               
.failureRateThreshold(50)
               
.waitDurationInOpenState(Duration.ofSeconds(60))
               
.permittedNumberOfCallsInHalfOpenState(3)
               
.build();
       
        CircuitBreaker circuitBreaker =
           
(CircuitBreakerStateMachine)
               
CircuitBreaker.of("DataServiceCb", circuitBreakerConfig);
       
       
return circuitBreaker;
   
}
}

CircuitBreakerConfig.java is the API for configuring the circuit breaker.

minimumNumberOfCalls: The minimum number of method calls/invokes that are required for the circuit breaker to start failure rate calculation. This parameter value is increased by one when the invoke source is invoked, regardless whether the invoke results in an exception or return with no exception.

slidingWindowType: Either count based or time in seconds based. In this article, count based sliding window is used.

slidingWindowSize: Provides the number of size of sliding window.

failureRateThreshold: Provides the threshold of failure rate in percentage.

waitDurationInOpenState: The duration for the circuit breaker to stay in OPEN state after circuit breaker transits from CLOSE to OPEN state.

permittedNumberOfCallsInHalfOpenState: The number of invoking/method calls to invoke source that is permitted when the circuit breaker is in HALF-OPEN state.


of() method is used to create the instance of circuit breaker. The first parameter DataServiceCb is the name for the circuit breaker, and the second parameter is the circuit breaker configuration.


Failure rate formula

In count based sliding window, the failure rate formula is the number of failures invoke / total number of invoking x 100%. The total number of invoking is the number of failures invoke + number of successes invoke.


The circuit breaker will start the failure rate calculation when the total number of invoke equals to minimumNumberOfCalls parameter. When the failure rate is equal or greater than the failureRateThreshold parameter, the Circuit Breaker transits from the CLOSE state of OPEN state.


When a circuit breaker collects the metrics, the total number of invoke is never exceed the slidingWindowSize parameter. For example, suppose the slidingWindowSize is four and the number of successes invoke is four. If there is fifth success invokes, a circuit breaker will not increase the number of successes invoke by one, but stops at the number that is provided in slidingWindowSize parameter. If the fifth invoke is a failure invoke, then circuit breaker will decrease the number of successes invoke by one, and increases the number of failures invoke by one. Therefore, circuit breaker always keeps the total number of invoke equals to slidingWindowSize.


Circuite Breaker in action

Try to execute the source code provided in this article, uses a web browser and send a request to this URL: http://localhost:8080/test?simulatedError=0 to test the circuit breaker.


There is no result in browser screen, but in the SpringToolSuite/Eclipse console. With the URL, the console will show this:

testresult: data
Circuit Breaker Statistic:
--------------------------
State: CLOSED
Failure rate: -1.0
Failure invoke count: 0
Success invoke count: 1
CallNotPermitted count: 0
--------------------------

/test is the RESTFul service created in RestfulService.java:

@RestController
public class RestfulService {
   
@Autowired private CircuitBreaker circuitBreaker;
   
   
@GetMapping("/test")
   
public void test(@RequestParam(required=false) String simulatedError) {
       
String error = simulatedError == null ? "":simulatedError;

       
try {
           
Supplier<String> sup=()->{
               
if(error.equals("1"))
                   
throw new IllegalStateException();
               
               
return "data";
           
};
           
            String test = CircuitBreaker
                .decorateSupplier
(
                   
circuitBreaker, sup
               
)
               
.get();
           
           
            System.out.println
("testresult: "+test);
       
}
       
catch(IllegalStateException excp) {
           
System.out.println("IllegalStateException");
       
}
       
catch(CallNotPermittedException excp) {       
           
System.out.println("CallNotPermittedException");
       
}
       
       
showStatistic();
   
}
   
   
private void showStatistic() {
       
Metrics met = circuitBreaker.getMetrics();
       
        System.out.println
("Circuit Breaker Statistic:");
        System.out.println
("--------------------------");
        System.out.println
("State: "+
                circuitBreaker.getState
());
        System.out.println
("Failure rate: "+
            met.getFailureRate
());
        System.out.println
("Failure invoke count: "+
            met.getNumberOfFailedCalls
());
        System.out.println
("Success invoke count: "+
            met.getNumberOfSuccessfulCalls
());
        System.out.println
("CallNotPermitted count: "+
                met.getNumberOfNotPermittedCalls
());       
        System.out.println
("--------------------------");
   
}
}


RestfulService.java creates a Supplier. This supplier is used to simulate the remote service. The supplier simply returns a String "data". When the simulatedError parameter has a value of 1, then the supplier will simulate a service error by throwing the IllegalStateException:

            Supplier<String> sup=()->{
               
if(error.equals("1"))
                   
throw new IllegalStateException();
               
               
return "data";
           
};

Therefore, When the supplier return data successfully, the circuit breaker will increase the number of successes invoke, otherwise if supplier throws the IllegalStateException, then circuit breaker will increase the number of failures invoke. In order for the circuit breaker to record the number of success and failure invoke, the circuit breaker must decorate the supplier:

            String test = CircuitBreaker
                .decorateSupplier
(
                   
circuitBreaker, sup
               
)
               
.get();
           
           
            System.out.println
("testresult: "+test);

get() method is invoked to execute the supplier. The restful service, then prints the value of the test variable on screen. If the restful service detects the IllegalStateException, then the console will show IllegalStateException, or CallNotPermittedException when CallNotPermittedException is detected. After all, the restful service invokes showStatistic() method to show the metric data collected by the circute breaker. Therefore, when the /test is firstly executed, the state is in CLOSE state. When the application is just started, executes the /test with simulatedError=0. Then executes another /test request with simulatedError=1. Observed that the statistic shows that the circuit breaker transits to OPEN state because the failure rate reaches 50% of failure threshold.


IllegalStateException
Circuit Breaker Statistic:
--------------------------
State: OPEN
Failure rate: 50.0
Failure invoke count: 1
Success invoke count: 1
CallNotPermitted count: 0
--------------------------

The circuit breaker will stay in OPEN state for 60 seconds, according to waitDurationInOpenState parameter. Any invoke during that 60 seconds, circuit breaker will throw CallNotPermittedException.

CallNotPermittedException
Circuit Breaker Statistic:
--------------------------
State: OPEN
Failure rate: 100.0
Failure invoke count: 2
Success invoke count: 0
CallNotPermitted count: 1
--------------------------
    

After the 60 seconds have elapsed, the circuit breaker transits to HALF-OPEN state. When in HALF-OPEN state, the circuit breaker will permit the invoke but limited to the number specified in permittedNumberOfCallsInHalfOpenState parameter.

IllegalStateException
Circuit Breaker Statistic:
--------------------------
State: HALF_OPEN
Failure rate: -1.0
Failure invoke count: 1
Success invoke count: 0
CallNotPermitted count: 0
--------------------------

The Circuit breaker will start the statistic collection also in HALF-OPEN state. If the failure rate equals to or more than failureRateThreshold, the circuit breaker transits back to OPEN state. If the number of success invoke equals to the permittedNumberOfCallsInHalfOpenState parameter and the failure rate is less than the failureRateThreshold, the state transits back to CLOSE state.


Type of Threshold

In this article, the application configures circuit breaker for failureRateThreshold. The failureRateThreshold is calculated based on the number of success and failure invoke. Besides the failureRateThreshold, there is another type of threshold, which is slowCallRateThreshold. The slowCallRateThreshold is calculated based on the number of invoke that is slow in performance. The slowCallRateThreshold will increase the number of the slow call by one of the invoke's execution time is equals or more than 60 seconds. The 60 seconds is the default behavior for the circuit breaker. However, this article uses a simulated supplier which has no performance problem, so the slowCallRateThreshold is never reaching its threshold. When develop the application for production project, the design of circuit breaker must take both failureRateThreshold and slowCallRateThreshold into accounts.




Source code

SpringBootR4jCircuitBreaker.zip
File size: 5.89 KB (6,030 bytes)
MD5 checksum: E4B4F6F2C3110AFA69F369CD33C26F0D
Development environment: Java11, Spring Tool Suite 4, SpringBoot2.1.8






Copyright© 2019 by MillionStrengthKnowledge.com

Legal Agreement