Implementing Resilient Microservices with Resilience4j
Microservices depend on multiple downstream systems, making them prone to failures like timeouts, slow responses, or service unavailability. Resilience4j provides tools to handle these gracefully, ensuring reliability.
In this post, we’ll implement Resilience4j with Spring Boot 3.x, using WebClient for non-blocking HTTP requests.
Problem Statement
Consider a CurrencyService
that fetches exchange rates from an external API. If the API is unresponsive or slow, it can affect the entire service. Our goal is to handle such failures using Resilience4j with a Circuit Breaker, Retry, and Fallback mechanisms.
Gradle Setup
Add the following dependencies to your build.gradle
:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'io.github.resilience4j:resilience4j-spring-boot3:2.x.x'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-aop'
}
Configuration
Update application.yml
for Resilience4j configuration:
resilience4j:
circuitbreaker:
instances:
currencyService:
failure-rate-threshold: 50
wait-duration-in-open-state: 10s
permitted-number-of-calls-in-half-open-state: 2
sliding-window-size: 10
retry:
instances:
currencyService:
max-attempts: 3
wait-duration: 2s
timelimiter:
instances:
currencyService:
timeout-duration: 3s
Service with WebClient
Here’s how to use WebClient
with Resilience4j:
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.retry.annotation.Retry;
@Service
public class CurrencyService {
private final WebClient webClient;
public CurrencyService(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder.baseUrl("https://api.exchangerate-api.com/v4/latest").build();
}
@CircuitBreaker(name = "currencyService", fallbackMethod = "fallbackForCurrencyService")
@Retry(name = "currencyService")
public String getExchangeRates(String currency) {
return webClient.get()
.uri("/{currency}", currency)
.retrieve()
.bodyToMono(String.class)
.block();
}
public String fallbackForCurrencyService(String currency, Throwable throwable) {
return "Fallback response for " + currency + ": { 'USD': 1, 'EUR': 0.85 }";
}
}
Controller
Expose an API to test the service:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CurrencyController {
private final CurrencyService currencyService;
public CurrencyController(CurrencyService currencyService) {
this.currencyService = currencyService;
}
@GetMapping("/api/rates/{currency}")
public String getExchangeRates(@PathVariable String currency) {
return currencyService.getExchangeRates(currency);
}
}
Flow of requests
**Note — source code for the above diagram — link
Monitoring Circuit States
- Enable Actuator Add the following to
application.yml
:
management:
endpoints:
web:
exposure:
include: health, metrics, resilience4j.circuitbreaker
- Monitor Metrics Access circuit breaker metrics via actuator at
/actuator/metrics/resilience4j.circuitbreaker
. - Detailed Insights For more details, you can enable
Resilience4j
’s Prometheus or Micrometer integration for visualization using tools like Grafana.
Simulate Failures
Modify the baseUrl
in CurrencyService
to an invalid URL. Observe:
- Retry: Attempts to fetch data multiple times.
- Circuit Breaker: Tracks failures and transitions to Open state.
- Fallback: Returns a default response when the circuit is open.
Conclusion
Resilience4j ensures your microservices remain resilient under adverse conditions. Combining Circuit Breaker, Retry, and Fallback provides robust fault tolerance.
With Spring Boot 3.x and WebClient, you can build non-blocking, fault-tolerant APIs ready for modern distributed architectures. Would you like additional insights into Prometheus integration or advanced configuration?
— — — — —
Let me know your thoughts/feedback in the comment section. Clap this story if found useful and follow me for more such content.