Hystrix Circuit breaker pattern with Spring Boot

In this article, 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 a 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

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’


Module-1: Rest Producer

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

Module-2: Rest Consumer 

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

Popular posts from this blog

Learn Java 8 streams with an example - print odd/even numbers from Array and List

Java, Spring Boot Mini Project - Library Management System - Download

Java - Blowfish Encryption and decryption Example

Java - DES Encryption and Decryption example

Google Cloud Storage + Spring Boot - File Upload, Download, and Delete

ReactJS - Bootstrap - Buttons

Spring Boot 3 + Spring Security 6 + Thymeleaf - Registration and Login Example

File Upload, Download, And Delete - Azure Blob Storage + Spring Boot Example

Java - How to Count the Number of Occurrences of Substring in a String

Top 5 Java ORM tools - 2024