Quick Start :Hystrix Circuit breaker pattern with Spring Boot

In this blog, we will go through how to implement the circuit breaker design pattern using Hystrix and Spring Boot
What is Hystrix?
Hystrix is the fault tolerance library. Using this library we can implement a circuit breaker design pattern. Hystrix is watching methods for failing calls to related services. If there is such a failure, it will open the circuit and forward the call to a fallback method. The library will tolerate failures up to a threshold. Beyond that, it leaves the circuit open. Which means, it will forward all subsequent calls to the fallback method, to prevent future failures. This creates a time buffer for the related service to recover from its failing state.
For quick start following technologies stack being used:

  • Spring Boot 2.1.1.RELEASE
  • Spring 5.1.3.RELEASE
  • Hystrix 
  • Maven 3
  • JDK 1.8
  • Eclipse Oxygen

1)Project Structure
To demonstrate the circuit breaker design pattern we need a web service first. Name it ‘REST Producer’, because it provides data for the Hystrix-enabled ‘REST Consumer’

2)Rest Producer
Maven/Dependency Management [pom.xml] 
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.1.1.RELEASE</version>
 </parent>
 <groupId>com.knowledgefactory</groupId>
 <artifactId>springboot-rest-producer</artifactId>
 <packaging>jar</packaging>
 <version>0.0.1-SNAPSHOT</version>
 <name>springboot-rest-producer</name>
<properties>
  <java.version>1.8</java.version>
 </properties>
<dependencies>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter</artifactId>
  </dependency>
  <!-- spring mvc, rest -->
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
</dependencies>
<build>
  <plugins>
    <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
   </plugin>
  </plugins>
 </build>
</project>
Controller
package com.knowledgefactory.knowledgefactorydemo;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Controller {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
 public ResponseEntity<String> listAllUsers() {
  return new ResponseEntity<String>("Rest producer produced data", HttpStatus.OK);
 }
}
Spring Boot
package com.knowledgefactory.knowledgefactorydemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class KnowledgefactorydemoApplication {
public static void main(String[] args) {
SpringApplication.run(KnowledgefactorydemoApplication.class, args);
 }
}
application.properties
server.port=9094
3)Rest Consumer with hystrix
Maven/Dependency Management [pom.xml] 
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
<artifactId>spring-rest-hystrix-consumer</artifactId>
 <packaging>jar</packaging>
 <name>spring-rest-hystrix-consumer</name>
 <version>1.0</version>
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.1.1.RELEASE</version>
 </parent>
<!-- Java 8 -->
 <properties>
  <java.version>1.8</java.version>
  <downloadSources>true</downloadSources>
  <downloadJavadocs>true</downloadJavadocs>
 </properties>
<dependencies>
<!-- spring mvc, rest -->
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  </dependency>
<!-- unit test rest -->
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
  </dependency>
          </dependencies>
 <dependencyManagement>
  <dependencies>
   <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-dependencies</artifactId>
    <version>Greenwich.RELEASE</version>
    <type>pom</type>
    <scope>import</scope>
   </dependency>
  </dependencies>
 </dependencyManagement>
<build>
  <plugins>
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
                       </plugins>
</build>
 <groupId>com.knowledgefactory</groupId>
 <url>www.knowledgefactory.net</url>
</project>
Controller
package com.knowledgefactory.knowledgefactorydemo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Controller {
 @Autowired
 ServiceLayer service;
 @RequestMapping(value = "/test", method = RequestMethod.GET)
 public ResponseEntity<String> listAllUsers() {
  return new ResponseEntity<String>(service.getService(), HttpStatus.OK);
 }
}
Service 
package com.knowledgefactory.knowledgefactorydemo;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
@Service
public class ServiceLayer {
@HystrixCommand(fallbackMethod = "fallbackmethod")
 public String getService() {
  final String uri = "http://localhost:9094/hello";
RestTemplate restTemplate = new RestTemplate();
  String result = restTemplate.getForObject(uri, String.class);
return result;
 }
 private String fallbackmethod() {
  return "Service failed";
 }
}
Spring Boot
package com.knowledgefactory.knowledgefactorydemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
@SpringBootApplication
@EnableCircuitBreaker
public class KnowledgefactorydemoApplication {
  public static void main(String[] args) {
         SpringApplication.run(KnowledgefactorydemoApplication.class, args);
     }
}
application.properties
server.port=9091
To see a Hystix circuit breaker in action we’re starting our ‘REST Consumer’ and pointing our browser to http://localhost:9091/test. Under normal circumstances, the following will be shown:

{Rest producer produced data}

To simulate a failure of our ‘REST Producer’, we’ll simply stop it, and after we finished refreshing the browser we should see a generic message, returned from the fallback method in our @Service:

{Service Failed}

Notes
The @EnableCircuitBreaker annotation will scan the classpath for any compatible Circuit Breaker implementation.
For the Circuit Breaker to work, Hystix will scan @Component or @Service annotated classes for @HystixCommand annotated methods, implement a proxy for it, and monitor its calls.

Comments