Wednesday 1 August 2018

CircuitBreaker/Hystrix - Microservices - Spring Boot

Hystrix

If you have, let’s say 3 services, A calls → B, and B calls → C service. What if, a failure happened at B? The error will cascade down to service C, right?.
A -> B (failure) -> C
Another example, lets say a service A calls a remote service R, and for some reason the remote service is down. How can we handle such a situation?
What we would like to do is stop failures from cascading down, and provide a way to self-heal, which improves the system’s overall resiliency.
Hystrix is the implementation of Circuit Breaker pattern, which gives a control over latency and failure between distributed services.
The main idea is to stop cascading failures by failing fast and recover as soon as possible — Important aspects of fault-tolerant systems that self-heal.
So, we’ll add Hystrix to gallery service, and we’ll simulate a failure at image service. In the pom.xml file
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
In the spring boot main class
// ...@EnableCircuitBreaker      // Enable circuit breakers
public class SpringEurekaGalleryApp {
  public static void main(String[] args) {
    SpringApplication.run(SpringEurekaGalleryApp.class, args);
  }
}
Spring looks for any method annotated with the @HystrixCommandannotation, and wraps that method so that Hystrix can monitor it.
Hystrix watches for failures in that method, and if failures reached a threshold (limit), Hystrix opens the circuit so that subsequent calls will automatically fail. Therefore, and while the circuit is open, Hystrix redirects calls to the fallback method.
So, In the controller class, update getGallery(), add annotation and fallback method.

package com.eureka.gallery.controllers;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.env.Environment;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.client.RestTemplate;
import com.eureka.gallery.entities.Gallery;import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;

@RestController
@RequestMapping("/")public class HomeController {
    @Autowired
    private RestTemplate restTemplate;

    @HystrixCommand(fallbackMethod = "fallback")
    @RequestMapping("/{id}")
    public Gallery getGallery(@PathVariable final int id) {
        // create gallery object        Gallery gallery = new Gallery();
        gallery.setId(id);

        // get list of available images         @SuppressWarnings("unchecked")    // we'll throw an exception from image service to simulate a failure                List<Object> images = restTemplate.getForObject("http://image-service/images/", List.class);
        gallery.setImages(images);

        return gallery;
    }

    // a fallback method to be called if failure happened    public Gallery fallback(int galleryId, Throwable hystrixCommand) {
        return new Gallery(galleryId);
    }
}
In the controller class of image service, throw an exception in getImages()
throw new Exception("Images can't be fetched");
Now, go to the browser, and hit localhost:8762/gallery/1. You should get an empty gallery object (no images).
{
    "id": 1,
    "images": null
}

No comments:

Post a Comment