Learnitweb

Implementing Circuit Breaker Pattern with Feign Client

Introduction

In this tutorial, we’ll implement Circuit Breaker Pattern with Feign Client. Sometimes, we don’t want to show the error page and gracefully handle the response. We may choose to return a default or custom response in case one of the microservice is down.

We can do this by implementing Circuit Breaker Pattern with Feign Client.

Dependency

In this tutorial, we’ll continue using our earlier examples. We’ll shutdown the Inventory Service and then try to access the Product Service. We’ll add a fallback response from the Product service in case Inventory service is down.

Add the following dependency in the Product Service.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId> </dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>

InventoryFallback

Earlier, we created an InventoryFeignClient. In the same package we have created our InventoryFallback. This returns a fallback response in case the actual service is down.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
package com.learnitweb.productservice.client;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import com.learnitweb.productservice.dto.InventoryDto;
@Component
public class InventoryFallback implements InventoryFeignClient {
@Override
public ResponseEntity<InventoryDto> getProductInventory(String name, String correlationId) {
InventoryDto inventoryDto = new InventoryDto();
inventoryDto.setProductName("some default product name");
inventoryDto.setQuantityRemaining(0);
return new ResponseEntity<InventoryDto>(inventoryDto, HttpStatus.OK);
}
}
package com.learnitweb.productservice.client; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import com.learnitweb.productservice.dto.InventoryDto; @Component public class InventoryFallback implements InventoryFeignClient { @Override public ResponseEntity<InventoryDto> getProductInventory(String name, String correlationId) { InventoryDto inventoryDto = new InventoryDto(); inventoryDto.setProductName("some default product name"); inventoryDto.setQuantityRemaining(0); return new ResponseEntity<InventoryDto>(inventoryDto, HttpStatus.OK); } }
package com.learnitweb.productservice.client;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;

import com.learnitweb.productservice.dto.InventoryDto;

@Component
public class InventoryFallback implements InventoryFeignClient {

	@Override
	public ResponseEntity<InventoryDto> getProductInventory(String name, String correlationId) {
		InventoryDto inventoryDto = new InventoryDto();
		inventoryDto.setProductName("some default product name");
		inventoryDto.setQuantityRemaining(0);
		return new ResponseEntity<InventoryDto>(inventoryDto, HttpStatus.OK);
	}

}

Now, modify the InventoryFeignClient to specify the fallback class.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@FeignClient(name = "InventoryService", fallback = InventoryFallback.class)
public interface InventoryFeignClient {
@GetMapping("/api/inventory/{name}")
public ResponseEntity<InventoryDto> getProductInventory(@PathVariable("name") String name,
@RequestHeader("eshop-correlation-id") String correlationId);
}
@FeignClient(name = "InventoryService", fallback = InventoryFallback.class) public interface InventoryFeignClient { @GetMapping("/api/inventory/{name}") public ResponseEntity<InventoryDto> getProductInventory(@PathVariable("name") String name, @RequestHeader("eshop-correlation-id") String correlationId); }
@FeignClient(name = "InventoryService", fallback = InventoryFallback.class)
public interface InventoryFeignClient {

	@GetMapping("/api/inventory/{name}")
	public ResponseEntity<InventoryDto> getProductInventory(@PathVariable("name") String name,
			@RequestHeader("eshop-correlation-id") String correlationId);

}

Test the changes

To test the changes start Eureka server, Gateway server and Product service. Do not start the Inventory Service.

Accessing the following endpoint should return fallback response:

localhost:8072/eshop/productservice/api/inventory/car

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
{
"productName": "some default product name",
"quantityRemaining": 0
}
{ "productName": "some default product name", "quantityRemaining": 0 }
{
    "productName": "some default product name",
    "quantityRemaining": 0
}