Resilience4J Circuit Breaker

Article 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 functional programming style. Invoke source is one or more code statements that invoke the remote service. Circuit breaker pattern 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 invoke source.

(5) Similar to CLOSE state, circuit breaker records the statistic of success and failure of invoke during the 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

@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;
}
}

io.github.resilience4j.circuitbreaker.CircuitBreakerConfig.javais 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 invoke/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

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 failureRateThresholdparameter, the Circuit Breaker transits from the CLOSE state of OPEN state.

When a circuit breaker collects the metrics, the total number of invoke never exceed the slidingWindowSize parameter. For example, suppose the slidingWindowSizeis four, and the number of success invoke is also four. If there is fifth success invokes, a circuit breaker will not increase the number of success invoke by one, but stops at the number that is provided in slidingWindowSizeparameter. If the fifth invoke is a failure invoke, then circuit breaker will decrease the number of success 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.

Circuit Breaker in action

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
--------------------------

/testis a 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 value “data”. When the simulatedErrorparameter 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 returns data successfully, the circuit breaker will increase the number of success invoke. If supplier throws IllegalStateException, then circuit breaker will increase the number of failure invoke. In order for circuit breaker to record the number of success and failure invoke, the circuit breaker must decorate the supplier:

             
System.out.println("testresult: "+test);
}
catch(IllegalStateException excp) {
System.out.println("IllegalStateException");
}
catch(CallNotPermittedException excp) {
System.out.println("CallNotPermittedException");
}
showStatistic();

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 catches the IllegalStateException, then the console will show a string value of ”IllegalStateException”, or ”CallNotPermittedException” when CallNotPermittedException is caught. After all, the restful service invokes showStatistic()method to show the metric data that is 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 /testrequest 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 inpermittedNumberOfCallsInHalfOpenState 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 also start the statistic collection 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 permittedNumberOfCallsInHalfOpenStateparameter and the failure rate is less than the failurRateThreshold, the state transits back to CLOSE state.

Type of Threshold

Source code

I am very interested in Java, web app and mobile app development. I enjoy doing R&D in Java during my spare time

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store