Implementing Resilience Patterns
1. Adding Resilience4j Dependencies
Example: Resilience4j dependencies
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot3</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. Implementing Circuit Breaker (@CircuitBreaker)
Example: Circuit breaker on external service call
@CircuitBreaker(name = "userApi", fallbackMethod = "fallback")
public UserDto get(Long id) { return userClient.get(id); }
public UserDto fallback(Long id, Throwable t) { return UserDto.unknown(id); }
3. Configuring Circuit Breaker States (open, closed, half-open)
State Machine
CLOSED → (failureRate ≥ threshold) → OPEN → (waitDuration) → HALF_OPEN → (success) → CLOSED
↓ (failure)
OPEN
Example: Circuit breaker thresholds configuration
resilience4j:
circuitbreaker:
instances:
userApi:
slidingWindowSize: 20
failureRateThreshold: 50
waitDurationInOpenState: 10s
permittedNumberOfCallsInHalfOpenState: 3
minimumNumberOfCalls: 10
4. Implementing Retry Mechanism (@Retry)
Example: Retry on external service call
@Retry(name = "userApi", fallbackMethod = "fallback")
public UserDto get(Long id) { return userClient.get(id); }
5. Configuring Retry Attempts and Delays
Example: Retry with exponential backoff configuration
resilience4j:
retry:
instances:
userApi:
maxAttempts: 3
waitDuration: 200ms
enableExponentialBackoff: true
exponentialBackoffMultiplier: 2
retryExceptions:
- java.io.IOException
- org.springframework.web.client.HttpServerErrorException
6. Implementing Rate Limiter (@RateLimiter)
Example: Rate limiter: 100 requests per second
resilience4j:
ratelimiter:
instances:
userApi:
limitForPeriod: 100
limitRefreshPeriod: 1s
timeoutDuration: 0
Example: Apply rate limiter annotation
@RateLimiter(name = "userApi") public UserDto get(Long id) { /* … */ }
7. Implementing Bulkhead Pattern (@Bulkhead)
| Type |
Behavior |
SEMAPHORE |
Limit concurrent calls (lightweight) |
THREADPOOL |
Isolate in dedicated thread pool |
Example: Semaphore bulkhead
@Bulkhead(name = "userApi", type = Bulkhead.Type.SEMAPHORE)
public UserDto get(Long id) { /* … */ }
8. Implementing Time Limiter (@TimeLimiter)
Example: Time-limit async call
@TimeLimiter(name = "userApi", fallbackMethod = "fallback")
public CompletionStage<UserDto> getAsync(Long id) {
return CompletableFuture.supplyAsync(() -> userClient.get(id));
}
9. Monitoring Resilience Metrics (Actuator)
| Endpoint |
Returns |
/actuator/circuitbreakers |
State of each CB |
/actuator/retries |
Retry counts |
/actuator/ratelimiters |
Rate limiter status |
/actuator/metrics/resilience4j.* |
Micrometer metrics |
10. Combining Multiple Resilience Patterns
Note: Default order:
Bulkhead → TimeLimiter → RateLimiter → CircuitBreaker → Retry → Fallback (outermost to innermost).
Example: Combine circuit breaker, retry, and bulkhead
@CircuitBreaker(name="userApi", fallbackMethod="fb")
@Retry(name="userApi")
@Bulkhead(name="userApi")
public UserDto get(Long id) { return userClient.get(id); }
11. Using Fallback Methods
| Rule |
Detail |
| Same return type |
Required |
| Same params + extra Throwable |
Last param is the exception |
| Multiple fallbacks |
Most-specific Throwable wins |