[Spring Boot 3] Default Aspect Order places Retry outside CircuitBreaker, causing inflated failure counts
Description
In the current Spring Boot 3 auto-configuration, the default aspectOrder values cause @Retry to wrap @CircuitBreaker.
This results in a logical error where a single operation with multiple retries is recorded as multiple failures by the CircuitBreaker, rather than a single failed unit of work.
Analysis
I investigated the default property values in the autoconfigure modules:
- RetryProperties.java:
retryAspectOrderdefaults toOrdered.LOWEST_PRECEDENCE - 4. - CircuitBreakerProperties.java:
circuitBreakerAspectOrderdefaults toOrdered.LOWEST_PRECEDENCE - 3.
Since Spring's Ordered interface prioritizes lower values as "Outer/First":
-4 < -3, so Retry runs first (Outer).- CircuitBreaker runs second (Inner).
Reproduction Steps
- Create a Service method annotated with both:
@Retry(maxAttempts=3)@CircuitBreaker(name="test") - Throw a
RuntimeExceptionfrom the method. - Check Actuator metrics:
resilience4j.circuitbreaker.calls(kind="failed"). - Observed: Value is
3.0(One failure recorded per retry attempt). - Expected: Value should be
1.0(The CircuitBreaker should wrap the entire retryable operation).
Proposed Solution
The default circuitBreakerAspectOrder in CircuitBreakerProperties.java should be set to a lower value (higher priority) than RetryProperties to ensure it wraps the Retry aspect by default.
Temporary Workaround
For users currently facing this issue, you can enforce the correct order manually in application.properties:
# Force Circuit Breaker to be Outer (runs first)
resilience4j.circuitbreaker.circuitBreakerAspectOrder=1
# Force Retry to be Inner (runs second)
resilience4j.retry.retryAspectOrder=2
**Contribution**
I am happy to submit a Pull Request to adjust these default values if this alignment fits the roadmap.Source: resilience4j/resilience4j