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"}"
\

Legal experts are concerned that transforming ESMA into the “European SEC” may hinder the licensing of crypto and fintech in the region. The European Commission’s proposal to expand the powers of the European Securities and Markets Authority (ESMA) is raising concerns about the centralization of the bloc’s licensing regime, despite signaling deeper institutional ambitions for its capital markets structure.On Thursday, the Commission published a package proposing to “direct supervisory competences” for key pieces of market infrastructure, including crypto-asset service providers (CASPs), trading venues and central counterparties to ESMA, Cointelegraph reported.Concerningly, the ESMA’s jurisdiction would extend to both the supervision and licensing of all European crypto and financial technology (fintech) firms, potentially leading to slower licensing regimes and hindering startup development, according to Faustine Fleuret, head of public affairs at decentralized lending protocol Morpho.Read more

