Learn how to make your microservice calls resilient using the Circuit Breaker pattern with Resilience4j and Spring Boot — complete demo, step-by-step commands, class-by-class explanations, sample outputs, real-world use cases, and production tips.
In distributed systems, a failing downstream service can cascade and cause overall system outages. The Circuit Breaker pattern:
\ This reduces downtime, protects thread pools, keeps user experience reasonable, and prevents retry storms.
A two-service Maven demo:
hello-service (port 8081) — simple REST provider that intentionally fails intermittently.
\
End point
GET /api/hello
client-service (port 8080) — calls hello-service using RestTemplate and is protected by Resilience4j @CircuitBreaker with a fallback.
\
End point
GET /api/get-message
\ Run both (hello-service and client-service)
\ Then test
GET http://localhost:8080/api/get-message
This is a small, focused flow suitable for drawing a diagram
HelloServiceApplication.java
Standard @SpringBootApplication bootstrap class.
\
HelloController.java @RestController public class HelloController { private static int counter = 0; @GetMapping("/api/hello") public String sayHello() { counter++; // simulate intermittent failure: fail on every 3rd request if (counter % 3 == 0) { throw new RuntimeException("Simulated failure from Hello-Service!"); } return "Hello from Hello-Service! (count=" + counter + ")"; } }
\ Explanation: This controller intentionally throws a RuntimeException on periodic calls to simulate transient failures you’d see in real systems (DB outage, bad data, timeouts).
ClientServiceApplication.java
AppConfig.java @Configuration public class AppConfig { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }
\ Explanation: Provides a single RestTemplate bean. Ensure RestTemplate is a Spring bean so AOP/resilience proxies can work properly.
HelloClientService.java @Service public class HelloClientService { private final RestTemplate restTemplate; @Value("${hello.service.url}") private String helloServiceUrl; public HelloClientService(RestTemplate restTemplate) { this.restTemplate = restTemplate; } @CircuitBreaker(name = "helloService", fallbackMethod = "fallbackHello") public String getHelloMessage() { System.out.println("Calling hello service: " + helloServiceUrl); return restTemplate.getForObject(helloServiceUrl, String.class); } public String fallbackHello(Throwable t) { System.out.println("Fallback triggered: " + t); return "Hello Service is currently unavailable. Please try again later."; } }
Explanation (crucial bits)
@CircuitBreaker(name = "helloService", fallbackMethod = "fallbackHello") wraps the getHelloMessage() call in a circuit breaker. The name links to configuration properties.
\
fallbackHello(Throwable t) is called when the call fails according to the breaker rules.
The fallback must:
o Be in the same class o Have the same return type o Accept the original method parameters (none here) and a final Throwable parameter (or Exception/Throwable compatible with thrown exceptions)
\
Important: The method must be public, and the class must be a Spring bean (@Service), so proxy-based AOP works.
\
ClientController.java @RestController public class ClientController { private final HelloClientService helloClientService; public ClientController(HelloClientService helloClientService) { this.helloClientService = helloClientService; } @GetMapping("/api/get-message") public String getMessage() { return helloClientService.getHelloMessage(); } }
\ Explanation: Simple controller delegating to HelloClientService. This ensures the call goes through the proxy where the circuit breaker is applied.
Key configuration used in the demo
\
server.port=8080 spring.application.name=client-service hello.service.url=http://localhost:8081/api/hello resilience4j.circuitbreaker.instances.helloService.registerHealthIndicator=true resilience4j.circuitbreaker.instances.helloService.slidingWindowSize=5 resilience4j.circuitbreaker.instances.helloService.minimumNumberOfCalls=2 resilience4j.circuitbreaker.instances.helloService.failureRateThreshold=50 resilience4j.circuitbreaker.instances.helloService.waitDurationInOpenState=10s logging.level.io.github.resilience4j.circuitbreaker=DEBUG
\ Meaning of important properties
Visit: http://localhost:8081/api/hello
\ Returns → "Hello from Hello-Service!" (or throws simulated failure)
Visit: http://localhost:8080/api/get-message
Make a request
GET http://localhost:8080/api/get-message
\ Client logs
Calling hello service: http://localhost:8081/api/hello 2025-11-13T11:58:23.366+05:30 DEBUG 32692 --- [client-service] [nio-8080-exec-8] i.g.r.c.i.CircuitBreakerStateMachine : CircuitBreaker 'helloService' succeeded: 2025-11-13T11:58:23.366+05:30 DEBUG 32692 --- [client-service] [nio-8080-exec-8] i.g.r.c.i.CircuitBreakerStateMachine : Event SUCCESS published: 2025-11-13T11:58:23.366634+05:30[Asia/Calcutta]: CircuitBreaker 'helloService' recorded a successful call. Elapsed time: 15 ms
\ Response
Hello from Hello-Service! (count=4)
If you call repeatedly and hello-service throws RuntimeException on some requests:
● Successful calls: client returns the hello message.
● When a downstream call returns HTTP 500/exception:
o Resilience4j records the failure. o If failure rate exceeds threshold (e.g., 50% over sliding window), the Circuit becomes **OPEN**. o While OPEN, calls are short-circuited; **fallbackHello**() is immediately executed — no network call. \n **Client response while fallback active**
\ Client Response while active
Response
Hello Service is currently unavailable. Please try again later.
\ 
Sample client log sequence
Calling hello service: http://localhost:8081/api/hello 2025-11-13T12:00:55.842+05:30 DEBUG 32692 --- [client-service] [nio-8080-exec-1] i.g.r.c.i.CircuitBreakerStateMachine : CircuitBreaker 'helloService' recorded an exception as failure:
After waitDurationInOpenState (10s):
\ Sample logs you’ll see (realistic)
Calling hello service: http://localhost:8081/api/hello 2025-11-13T12:00:55.842+05:30 DEBUG 32692 --- [client-service] [nio-8080-exec-1] i.g.r.c.i.CircuitBreakerStateMachine : CircuitBreaker 'helloService' recorded an exception as failure 2025-11-13T12:00:55.847+05:30 DEBUG 32692 --- [client-service] [nio-8080-exec-1] i.g.r.c.i.CircuitBreakerStateMachine : Event ERROR published: 2025-11-13T12:00:55.847908200+05:30[Asia/Calcutta]: CircuitBreaker 'helloService' recorded an error: 'org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 : "{"timestamp":"2025-11-13T06:30:55.842+00:00","status":500,"error":"Internal Server Error","path":"/api/hello"}"'. Elapsed time: 8 ms Fallback triggered: org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 : "{"timestamp":"2025-11-13T06:30:55.842+00:00","status":500,"error":"Internal Server Error","path":"/api/hello"}"
\

