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
The application requires some configuration 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 this 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;
}
}
io.github.resilience4j.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 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
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 invoke 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 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 never exceed the slidingWindowSize
parameter. For example, suppose the slidingWindowSize
is 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 slidingWindowSize
parameter. 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
Try to execute the source code provided in this article, uses a web browser and sends 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 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 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 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 /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 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 permittedNumberOfCallsInHalfOpenState
parameter and the failure rate is less than the failurRateThreshold
, the state transits back to CLOSE state.
Type of Threshold
In this article, the application configures circuit breaker for failurRateThreshold
. The failurRateThreshold
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 when 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
Github: SpringBootR4jCircuitBreaker.zip
Development environment: Java11, Spring Tool Suite 4, SpringBoot2.1.8, Resilience4J 1.2.0
Originally published at https://millionstrengthknowledge.com/resource/springboot/cloud/r4jcb/r4jcb.html