Files
spring-boot-demo/resilience4j-circuit-breaker/README.md
T
asmhatre 320733265f Add resilience4j-circuit-breaker: Resilience4j 2.4.0 vs Spring Framework 7 core, on Boot 4.1
Companion module for the rewritten post 'Resilience4j Circuit Breaker in Spring Boot 4.1:
What It's Still For', reworked around Framework 7 now shipping @Retryable/@ConcurrencyLimit
in core. Covers what's still Resilience4j's job (circuit breaker, rate limiter, bulkhead's
bounded wait, fallback methods, Actuator/Micrometer metrics), the off-by-one between
maxAttempts and maxRetries, and two Boot-4.1 build breaks: spring-boot-starter-aop no longer
exists (renamed to spring-boot-starter-aspectj, proven with Maven Central metadata and the
renamed starter's own POM -- see resilience/docs/08-starter-aop-renamed-to-starter-aspectj.md
in this same repo), and the resulting fix uses that renamed starter directly rather than
assembling spring-aop + aspectjweaver by hand. Kept as its own module rather than a new
top-level repository, alongside the existing resilience/ module for the sibling Framework-7
post.
2026-09-18 08:40:50 +00:00

5.7 KiB

resilience4j-circuit-breaker

Companion module for the ankurm.com post "Resilience4j Circuit Breaker in Spring Boot 4.1: What It's Still For". Every claim in the post about the new @Retryable/@ConcurrencyLimit API in Spring Framework 7, and about how it does and doesn't overlap with Resilience4j, is backed by a file under docs/output/ produced by a real test run against real Maven Central artifacts.

Lives in this container repo (not as its own top-level repository) alongside ../resilience, the companion module for the sibling post on Framework 7's built-in @Retryable/@ConcurrencyLimit. The two modules overlap in theme by design — this one is entered from "I want a circuit breaker," that one from "what did Framework 7 just ship" — and intentionally keep separate demo apps rather than sharing one, since each post's transcripts need to stay independently reproducible from its own module.

Versions (verified against repo1.maven.org maven-metadata.xml, not aggregators)

Component Version Notes
JDK 25 (Temurin 25.0.4.1+1) latest LTS
Spring Boot 4.1.1 latest GA at time of writing; 4.2.0-M1 exists but is a milestone
Spring Framework 7.0.9 latest GA; 7.1.0-M1 exists but is a milestone
Resilience4j 2.4.0 (resilience4j-spring-boot4) depends internally on resilience4j-spring6, not a "spring7" module — see docs/01

Quickstart

./scripts/run-all.sh   # regenerates every file in docs/output/ from a real test run
./scripts/run.sh        # starts the app on :8080 to poke at by hand
curl localhost:8080/actuator/health
curl localhost:8080/actuator/circuitbreakers

Requires JDK 25 and Maven. First run must be online (Maven needs to fetch plugins into the local cache); -o works for subsequent builds.

What's demonstrated where

Area Source Test Transcript
Resilience4j circuit breaker: trip, stay open, half-open, recover R4jPaymentService CircuitBreakerTripAndRecoverTest 01
@Retryable: recovers from transient failure SpringRetryablePaymentService SpringRetryableTest 03a
@Retryable: no memory between calls same same 03b
@Retryable: self-invocation trap same same 03c
Resilience4j @Retry side-by-side (maxAttempts counts differently than maxRetries) R4jRetryService R4jRetryTest 03d, 03e
@ConcurrencyLimit BLOCK policy ConcurrencyLimitedService ConcurrencyLimitTest 04a
@ConcurrencyLimit REJECT policy same same 04b
Resilience4j @Bulkhead (bounded wait) for comparison R4jBulkheadService same 04c
Real /actuator/health + /actuator/circuitbreakers with a breaker OPEN R4jPaymentService ActuatorHealthTest 05

Endpoints (from scripts/run.sh)

Endpoint Purpose
GET /actuator/health includes circuit breaker health when management.health.circuitbreakers.enabled=true
GET /actuator/circuitbreakers live circuit breaker state
GET /actuator/circuitbreakerevents event stream of state transitions
GET /actuator/metrics includes resilience4j.circuitbreaker.* Micrometer series

There is no custom diagnostic endpoint in this repo — the standard Actuator set above already exposes everything the post needed, so nothing has to be deleted before shipping.

Note on /actuator/health in 2.4.0: with management.endpoint.health.show-details: always, /actuator/health reports only an aggregate "circuitBreakers":{"status":"UNKNOWN"} — no per-instance breakdown. The per-breaker detail (state, failureRate, bufferedCalls, etc.) lives at /actuator/circuitbreakers instead. Real captured output of both, side by side, with the breaker actually OPEN: docs/output/05-actuator-health-tripped.txt.

Documentation chapters

  1. Two resilience stacks on one classpath — what moved into Spring Framework 7 core, what didn't, and two build breaks you'll hit getting there
  2. The circuit breaker, verified
  3. @Retryable: retries, but no memory
  4. @ConcurrencyLimit vs Resilience4j's Bulkhead
  5. Production checklist: which one, for what

License

MIT — see LICENSE.