Have you ever faced problems consuming third party APIs? If so, using circuit breaker resilience can help you.

Context

Imagine that your application needs to call another API, but the other API is unstable. You keep calling the API but still get no answer. In this case, you can configure a circuit breaker, which is responsible for cutting the connection with the problematic API for a while, avoiding unnecessary and repetitive calls to a service that is unavailable.

Setting up a circuit breaker means your service can return a standard, pre-configured answer, and after a pre-set time, the mechanism will evaluate the connection; if the connection is better, the circuit breaker will allow connections again.

What is a Circuit Breaker?

Circuit breakers are based on three states:

  • CLOSED: when everything is functioning properly, the requests are forwarded to the service
  • OPEN: after the application gets successive errors or timeouts, the mechanism closes the connection and no longer sends the requests to the service
  • HALF-OPEN: a transitional state when the mechanism is evaluating whether the service is stable again by sending some requests and checking the response

 

Image courtesy of Resilience4j

The animation below illustrates a circuit breaker in action:

u3f6z484i74k0osz5r6z

 

 

Image courtesy of codecentricAvailable at media.graphassets

 

Case Study

To explain the use of circuit breakers, we will implement a solution using resilience4j in a Java Spring Boot application.

Spring Boot 2 already provides a starter for resilience:

org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j

So we will add this dependency on pom.xml:

<dependency>
   <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>

To configure the parameters, add this on your bootstrap.yml:

resilience4j.circuitbreaker:
 configs:
   default:
     failureRateThreshold: 25 # Percentage (%) of calls accepted with failure.
     slowCallRateThreshold: 25 # Percentage (%) of calls accepted with delay.


     slowCallDurationThreshold: 5000 # In milliseconds, maximum time of a call in a sincron API.
     permittedNumberOfCallsInHalfOpenState: 5 # Number of calls to evaluate if the circuit can close again.
     slidingWindowType: COUNT_BASED
     slidingWindowSize: 5 # Window size to evaluate the Thresholds.
     minimumNumberOfCalls: 2 # minimum number of calls to evaluate the Thresholds
     waitDurationInOpenState: 30000 # In milliseconds, time wich the circuit will be open to evaluate if it is possible to close the circuit again.
     ignoreExceptions: # Here you can add the exception you want to ignore on your metrics
       - org.springframework.web.client.HttpClientErrorException # Just a example

You can also check the documentation for more information.

Config Class Example

Let's look at an example. In this case, we'll first log the information that the circuit breaker state has changed:

@Configuration
@Slf4j
public class CircuitBreakerConfig {
   @Bean
   public RegistryEventConsumer<CircuitBreaker> consumer() {
       return new RegistryEventConsumer<CircuitBreaker>() {
           @Override
           public void onEntryAddedEvent(EntryAddedEvent<CircuitBreaker> entryAddedEvent) {
               entryAddedEvent.getAddedEntry()
                       .getEventPublisher()
                       .onStateTransition(
                               //You can add something you want to do when happened some state change
                               //EG: log the change
                               event -> log.info(event.toString())
                       );
           }

           @Override
           public void onEntryRemovedEvent(EntryRemovedEvent<CircuitBreaker> entryRemoveEvent) {
               //from abstract implementation
           }

           @Override
           public void onEntryReplacedEvent(EntryReplacedEvent<CircuitBreaker> entryReplacedEvent) {
               //from abstract implementation
           }
       };
   }
}

Below is an example of how to use a fallback method to return something when the circuit is open or some error occurs when the request is sent.

Note: the object named service is responsible for calling the API.

@RestController
@RequestMapping(value = "/clients")
@Slf4j
public class ClientController {

   private final ClientsService service;

   public ClientController(ClientsService service) {
       this.service = service;
   }

   @CircuitBreaker(name = "returnClientData", fallbackMethod = "returnClientDataFallback")
   @GetMapping(value = "/{socialNumber}", produces = {MediaType.APPLICATION_JSON_VALUE})
   public ResponseEntity<ClientDataDTO> returnClientData(@PathVariable @Valid String socialNumber) {
       return ResponseEntity.ok(service.clientData(socialNumber));
   }

   public ResponseEntity<ClientDataDTO> returnClientDataFallback(String socialNumber, Exception e) {
       log.debug(MessageFormat.format("Error to communicate to API Clients controller: socialNumber:{0} {1}", socialNumber, e));
       return ResponseEntity.ok(ClientDataDTO.builder()
               .name("John doe")
               .build());
   }
}
Conclusion

In this article, you learned how to avoid problems consuming APIs by using a circuit breaker, how to configure it in your Spring Boot Application, and also how to create a fallback method to return a standard response. 

Ready to try it in your project? Let me know how it goes in the comments below!

 
References

docs.spring.io Spring Cloud Circuit Breaker

Resilience4j Sprint Boot 2


Author

Ederson Silva

Ederson Silva is a Software Engineer at Avenue Code. He has 6 years of experience with Java, working with web applications in MVC architecture and microservices. He is also passionate about traveling, learning about new things and living new experiences.


New Horizons for Solution Architects

READ MORE

How to Run Rust from Python

READ MORE

Deep Dive into MuleSoft Internals - API Tracking

READ MORE