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