resilience-patterns
Configures and tests fault-tolerance patterns like Circuit Breakers and Retries in Spring Boot applications.
Install
mkdir -p .claude/skills/resilience-patterns && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/11840" && unzip -o skill.zip -d .claude/skills/resilience-patterns && rm skill.zipInstalls to .claude/skills/resilience-patterns
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Load when adding @CircuitBreaker, @Retry, @Bulkhead, @RateLimiter, or @TimeLimiter from Resilience4j, configuring WebClient or RestClient with retry operators, writing fallback methods, handling CircuitBreakerOpenException or BulkheadFullException, configuring resilience4j in application.yml (slidingWindowType, failureRateThreshold, waitDurationInOpenState), or testing circuit breaker state transitions with @SpringBootTest.Key capabilities
- →Implement Circuit Breaker patterns to prevent cascading failures
- →Configure Retry mechanisms with exponential backoff and jitter for transient failures
- →Apply Bulkhead patterns (Semaphore or Thread Pool) to limit concurrent calls
- →Configure Rate Limiter to control request rates to services
- →Implement Time Limiter to enforce execution deadlines for operations
- →Write fallback methods for resilience patterns
How it works
This skill guides the implementation of resilience patterns using Resilience4j annotations and configuration in Spring Boot 3. It covers Circuit Breaker, Retry, Bulkhead, Rate Limiter, and Time Limiter to prevent system failures.
Inputs & outputs
When to use resilience-patterns
- →Configuring Circuit Breaker thresholds
- →Implementing retry logic for external API calls
- →Writing fallback methods for failing services
- →Testing resilience transitions with SpringBootTest
About this skill
Resilience Patterns for Spring Boot (Resilience4j)
Dependency
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot3</artifactId>
</dependency>
<!-- AOP required for annotations -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
Circuit Breaker
Prevents cascading failures by short-circuiting calls to a failing dependency.
Configuration
resilience4j:
circuitbreaker:
instances:
payment-gateway:
register-health-indicator: true
sliding-window-type: COUNT_BASED
sliding-window-size: 10 # number of calls to evaluate
failure-rate-threshold: 50 # % failures to open the circuit
slow-call-rate-threshold: 50 # % slow calls to open the circuit
slow-call-duration-threshold: 2s
wait-duration-in-open-state: 30s # how long to stay OPEN before HALF_OPEN
permitted-number-of-calls-in-half-open-state: 5
automatic-transition-from-open-to-half-open-enabled: true
record-exceptions:
- java.io.IOException
- java.util.concurrent.TimeoutException
ignore-exceptions:
- com.example.order.exception.BusinessValidationException
Usage
@Service
@RequiredArgsConstructor
public class PaymentService {
@CircuitBreaker(name = "payment-gateway", fallbackMethod = "paymentFallback")
public PaymentResult charge(ChargeRequest request) {
return externalPaymentGateway.charge(request);
}
// Fallback — same return type, extra Throwable parameter
private PaymentResult paymentFallback(ChargeRequest request, Exception ex) {
log.warn("Payment gateway unavailable, queuing for retry chargeId={}", request.id(), ex);
pendingChargeQueue.enqueue(request);
return PaymentResult.queued(request.id());
}
}
States
CLOSED → (failure rate ≥ threshold) → OPEN → (waitDuration elapsed) → HALF_OPEN → (test calls succeed) → CLOSED
→ (test calls fail) → OPEN
CLOSED: Normal operation, all calls pass through.
OPEN: All calls fail immediately with CallNotPermittedException. Fallback is invoked.
HALF_OPEN: Limited test calls allowed. Determines if the dependency recovered.
Retry
Automatic retry with backoff for transient failures.
Configuration
resilience4j:
retry:
instances:
inventory-service:
max-attempts: 3
wait-duration: 500ms
enable-exponential-backoff: true
exponential-backoff-multiplier: 2 # 500ms, 1000ms, 2000ms
exponential-max-wait-duration: 10s
retry-exceptions:
- java.io.IOException
- org.springframework.web.client.ResourceAccessException
ignore-exceptions:
- com.example.exception.InvalidRequestException
Critical: Always add jitter to prevent thundering herd.
resilience4j:
retry:
instances:
inventory-service:
wait-duration: 500ms
enable-exponential-backoff: true
exponential-backoff-multiplier: 2
randomized-wait-factor: 0.5 # ±50% jitter applied to wait duration
Usage
@Retry(name = "inventory-service", fallbackMethod = "inventoryFallback")
@CircuitBreaker(name = "inventory-service") // Combine retry + circuit breaker
public InventoryStatus checkStock(String productId) {
return inventoryClient.getStock(productId);
}
private InventoryStatus inventoryFallback(String productId, Exception ex) {
log.warn("Inventory service unavailable, returning optimistic stock productId={}", productId, ex);
return InventoryStatus.assumeAvailable(productId);
}
Order matters: @Retry wraps @CircuitBreaker. Retry fires first; if the circuit is open, retries immediately fail.
Bulkhead — Concurrency Limiter
Limits the number of concurrent calls to a dependency. Prevents a slow service from consuming all threads.
Semaphore Bulkhead (default — blocks calling thread)
resilience4j:
bulkhead:
instances:
payment-gateway:
max-concurrent-calls: 20 # max simultaneous in-flight calls
max-wait-duration: 100ms # how long to wait for a permit before BulkheadFullException
@Bulkhead(name = "payment-gateway", type = Bulkhead.Type.SEMAPHORE,
fallbackMethod = "bulkheadFallback")
public PaymentResult charge(ChargeRequest request) { ... }
private PaymentResult bulkheadFallback(ChargeRequest request, BulkheadFullException ex) {
return PaymentResult.rejected("System is busy — please retry shortly");
}
Thread Pool Bulkhead (non-blocking reactive)
resilience4j:
thread-pool-bulkhead:
instances:
email-service:
max-thread-pool-size: 10
core-thread-pool-size: 5
queue-capacity: 50
@Bulkhead(name = "email-service", type = Bulkhead.Type.THREADPOOL)
public CompletableFuture<Void> sendEmail(EmailRequest request) {
return CompletableFuture.runAsync(() -> emailClient.send(request));
}
Rate Limiter
Limits calls per time period. Protects external APIs with rate limits.
resilience4j:
ratelimiter:
instances:
sendgrid-api:
limit-for-period: 100 # 100 calls per refresh period
limit-refresh-period: 1s
timeout-duration: 200ms # wait at most 200ms for a permit
@RateLimiter(name = "sendgrid-api", fallbackMethod = "rateLimitFallback")
public void sendEmail(EmailRequest request) {
sendgridClient.send(request);
}
private void rateLimitFallback(EmailRequest request, RequestNotPermitted ex) {
log.warn("Rate limit exceeded, queuing email recipient={}", request.to());
emailQueue.enqueue(request);
}
Time Limiter — Async Timeouts
Enforces a timeout on CompletableFuture or reactive operations. Use with @Bulkhead(THREADPOOL).
resilience4j:
timelimiter:
instances:
slow-report-service:
timeout-duration: 3s
cancel-running-future: true
@TimeLimiter(name = "slow-report-service", fallbackMethod = "reportTimeout")
@Bulkhead(name = "slow-report-service", type = Bulkhead.Type.THREADPOOL)
public CompletableFuture<Report> generateReport(ReportRequest request) {
return CompletableFuture.supplyAsync(() -> reportService.generate(request));
}
private CompletableFuture<Report> reportTimeout(ReportRequest request, TimeoutException ex) {
return CompletableFuture.completedFuture(Report.partial(request.id(), "Report is taking longer than expected"));
}
WebClient Retry (Reactive)
For reactive stacks — retry at the HTTP client level:
@Bean
public WebClient paymentWebClient() {
return WebClient.builder()
.baseUrl(paymentGatewayUrl)
.build();
}
public Mono<PaymentResponse> chargeReactive(ChargeRequest request) {
return webClient.post()
.uri("/charge")
.bodyValue(request)
.retrieve()
.onStatus(HttpStatusCode::is5xxServerError,
response -> Mono.error(new RetryableException("Gateway 5xx")))
.bodyToMono(PaymentResponse.class)
.retryWhen(Retry.backoff(3, Duration.ofMillis(500))
.maxBackoff(Duration.ofSeconds(5))
.jitter(0.5) // ±50% jitter
.filter(ex -> ex instanceof RetryableException)
.onRetryExhaustedThrow((spec, signal) ->
new PaymentGatewayException("All retries exhausted", signal.failure())));
}
Combining Patterns
Recommended combination for an external HTTP dependency:
@CircuitBreaker(name = "payment-gateway", fallbackMethod = "chargeFallback")
@Retry(name = "payment-gateway")
@Bulkhead(name = "payment-gateway")
public PaymentResult charge(ChargeRequest request) {
return externalGateway.charge(request);
}
Execution order (outer → inner): Bulkhead → CircuitBreaker → Retry → Method
Testing Circuit Breaker State
@SpringBootTest
class PaymentServiceResilienceTest {
@Autowired PaymentService paymentService;
@Autowired CircuitBreakerRegistry registry;
@MockBean ExternalPaymentGateway externalGateway;
@Test
void shouldOpenCircuitAfterFailureThreshold() {
// Arrange — configure gateway to always fail
given(externalGateway.charge(any())).willThrow(new IOException("gateway down"));
CircuitBreaker cb = registry.circuitBreaker("payment-gateway");
assertThat(cb.getState()).isEqualTo(CircuitBreaker.State.CLOSED);
// Act — trigger failures to exceed threshold (10 calls, 50% threshold = 5 failures)
for (int i = 0; i < 10; i++) {
try { paymentService.charge(aRequest()); } catch (Exception ignored) {}
}
// Assert — circuit opened
assertThat(cb.getState()).isEqualTo(CircuitBreaker.State.OPEN);
}
@Test
void shouldCallFallbackWhenCircuitOpen() {
CircuitBreaker cb = registry.circuitBreaker("payment-gateway");
cb.transitionToOpenState(); // force open for test
PaymentResult result = paymentService.charge(aRequest());
assertThat(result.status()).isEqualTo(PaymentStatus.QUEUED);
}
}
Pitfalls
| Pitfall | Fix |
|---|---|
| No jitter on retry backoff | Add randomized-wait-factor: 0.5 — prevents thundering herd at recovery |
| Retrying non-retryable exceptions | Whitelist retryable exceptions; ignore business errors (validation, 400s) |
| Circuit breaker wrapping circuit breaker | One CB per external dependency; do not nest CB annotations |
| Bulkhead maxWaitDuration=0 | At 0, any concurrent call beyond max-concurrent-calls immediately fails — set a small timeout for queuing |
| Fallback with different semantics | Fa |
Content truncated.
When not to use it
- →When the application does not use Spring Boot 3
- →When the dependencies are not managed by Maven or Gradle
- →When a simpler, non-Resilience4j based resilience solution is preferred
Prerequisites
Limitations
- →Requires `spring-boot-starter-aop` for annotations
- →Circuit Breaker wrapping another Circuit Breaker is a pitfall
- →TimeLimiter requires async execution and should be paired with THREADPOOL bulkhead
How it compares
This skill provides a Spring Boot 3 and Resilience4j-specific approach to implementing resilience patterns, offering annotation-based configuration and detailed examples, unlike generic resilience advice.
Compared to similar skills
resilience-patterns side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| resilience-patterns (this skill) | 0 | 4mo | No flags | Advanced |
| java-pro | 34 | 4mo | No flags | Advanced |
| java-pro | 0 | 6mo | No flags | Advanced |
| java-coding-standards | 16 | 4mo | No flags | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
java-pro
sickn33
Master Java 21+ with modern features like virtual threads, pattern matching, and Spring Boot 3.x. Expert in the latest Java ecosystem including GraalVM, Project Loom, and cloud-native patterns. Use PROACTIVELY for Java development, microservices architecture, or performance optimization.
java-pro
SpencerGeee
Master Java 21+ with modern features like virtual threads, pattern
java-coding-standards
affaan-m
Java coding standards for Spring Boot services: naming, immutability, Optional usage, streams, exceptions, generics, and project layout.
jpa-patterns
affaan-m
JPA/Hibernate patterns for entity design, relationships, query optimization, transactions, auditing, indexing, pagination, and pooling in Spring Boot.
backend-microservice-development
TencentBlueKing
后端微服务开发规范,涵盖目录结构、分层架构(API/Service/DAO)、依赖注入、配置管理、Spring Boot 最佳实践。当用户进行后端开发、创建新微服务、编写 Kotlin/Java 代码或设计服务架构时使用。
microservice-infrastructure
TencentBlueKing
微服务基础设施指南,涵盖条件配置、事件驱动架构、服务间通信、国际化与日志等微服务架构的核心基础设施。当用户实现服务间调用、配置多环境、实现异步通信、处理国际化或规范日志输出时使用。