Master java skills

Circuit Breaker using Spring Boot Hystrix

Hystrix is a library from Netflix that implements circuit breaker pattern. It is a latency and fault tolerance library for isolating points of access to remote systems, services or third party libraries. Thus it stops cascading failures and enables resilience in complex distributed systems.

Fallback – If a service call fails or takes too long to respond, Hystrix can provide a fallback response. It allows the application to degrade gracefully rather than failing right away.

In the below example, we will implement Hystix. We will create one microservice which calls another. However, we will keep another service down so that circuit breaker pattern will take place and fallback response will be given instead of an error message.

Create a spring starter project in STS

pom.xml – Make sure the version of spring-boot-starter-parent, java, spring-cloud.version remain same as given in the below 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>1.5.9.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	
	<groupId>com.sks</groupId>
	<artifactId>circuit-breaker</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>circuit-breaker</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
	</properties>
	<dependencies>
		<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>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<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>${spring-cloud.version}</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>
</project>

Springboot application class

package com.sks;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableHystrix
public class CircuitBreakerApplication {

	public static void main(String[] args) {
		SpringApplication.run(CircuitBreakerApplication.class, args);
	}
	
	@Bean
	public RestTemplate getRestTemplate() {
		return new RestTemplate();
	}

}

ExternalService.java

package com.sks;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class ExternalService {

	@Autowired
	private RestTemplate restTemplate;

	public String callExternalApi() {
		String result = restTemplate.getForObject("http://localhost:8080/api/hello1", String.class);
		return result;
	}
}

ApiController.java

package com.sks;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.HttpClientErrorException;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;

@RestController
public class ApiController {

	@Autowired
    private ExternalService externalService;

    @GetMapping("/test")
    @HystrixCommand(fallbackMethod = "fallbackResponse", 
    commandProperties = {
    	      @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000")})
    public String testCircuitBreaker() {
        return externalService.callExternalApi();
    }
    
    public String fallbackResponse(Throwable t) {
    	if (t instanceof HttpClientErrorException) {
            HttpClientErrorException ex = (HttpClientErrorException) t;
            if (ex.getStatusCode() == HttpStatus.NOT_FOUND) {
                return "Resource not found";
            }
        }
        return "Fallback response due to failure. Unable to connect to the backend service right not."
        		+ " Please try again later.";
    }
}

Start the service and test.