package com.example.demo.service;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import io.github.resilience4j.retry.annotation.Retry;
import io.github.resilience4j.bulkhead.annotation.Bulkhead;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class ResilientService {
private static final Logger logger = LoggerFactory.getLogger(ResilientService.class);
private final RestTemplate restTemplate;
public ResilientService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@CircuitBreaker(name = "externalAPI", fallbackMethod = "fallbackResponse")
@Retry(name = "externalAPI")
public String callExternalAPI() {
logger.info("Calling external API");
return restTemplate.getForObject("https://api.example.com/data", String.class);
}
@RateLimiter(name = "userService")
public String rateLimitedOperation() {
logger.info("Executing rate limited operation");
return "Operation completed";
}
@Bulkhead(name = "processingService", type = Bulkhead.Type.THREADPOOL)
public String isolatedOperation() {
logger.info("Executing isolated operation");
// Heavy processing
return "Processing complete";
}
@CircuitBreaker(name = "paymentService", fallbackMethod = "paymentFallback")
@Retry(name = "paymentService", fallbackMethod = "paymentFallback")
public String processPayment(String orderId) {
logger.info("Processing payment for order: {}", orderId);
// Call payment service
return "Payment successful";
}
// Fallback methods
private String fallbackResponse(Exception e) {
logger.error("Fallback triggered due to: {}", e.getMessage());
return "Service temporarily unavailable. Using cached data.";
}
private String paymentFallback(String orderId, Exception e) {
logger.error("Payment fallback for order {} due to: {}", orderId, e.getMessage());
return "Payment queued for processing";
}
}
resilience4j:
circuitbreaker:
instances:
externalAPI:
registerHealthIndicator: true
slidingWindowSize: 10
minimumNumberOfCalls: 5
permittedNumberOfCallsInHalfOpenState: 3
automaticTransitionFromOpenToHalfOpenEnabled: true
waitDurationInOpenState: 10s
failureRateThreshold: 50
slowCallRateThreshold: 100
slowCallDurationThreshold: 2s
paymentService:
slidingWindowSize: 20
failureRateThreshold: 60
waitDurationInOpenState: 20s
retry:
instances:
externalAPI:
maxAttempts: 3
waitDuration: 1s
enableExponentialBackoff: true
exponentialBackoffMultiplier: 2
retryExceptions:
- org.springframework.web.client.RestClientException
ignoreExceptions:
- java.lang.IllegalArgumentException
paymentService:
maxAttempts: 5
waitDuration: 2s
ratelimiter:
instances:
userService:
limitForPeriod: 100
limitRefreshPeriod: 1s
timeoutDuration: 0s
bulkhead:
instances:
processingService:
maxConcurrentCalls: 10
maxWaitDuration: 100ms
timelimiter:
instances:
externalAPI:
timeoutDuration: 5s
Resilience4j provides resilience patterns for fault tolerance. Circuit breakers prevent cascading failures—open after threshold failures, allow retry after timeout. Rate limiters control request rates. Retry mechanisms handle transient failures. Bulkheads isolate resources preventing exhaustion. Time limiters enforce execution deadlines. Fallback methods provide degraded functionality. I combine patterns for robust microservices. Metrics expose circuit states, failure rates. Spring Boot integration uses annotations—@CircuitBreaker, @RateLimiter, @Retry. Configuration tunes thresholds, timeouts, limits. Resilience4j replaces Netflix Hystrix with lighter, more flexible implementation. Proper resilience design prevents single points of failure and improves system availability under stress.
Related snips
export interface RetryOptions {
retries: number;
baseMs: number;
maxMs: number;
signal?: AbortSignal;
onRetry?: (attempt: number, delay: number, err: unknown) => void;
Exponential backoff with jitter for retries
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
createdAt: String!
GraphQL API with Spring Boot
package com.example.starter.config;
import com.example.starter.properties.CustomProperties;
import com.example.starter.service.CustomService;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
Custom Spring Boot starters
package com.example.demo.config;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.apache.kafka.common.serialization.StringSerializer;
Messaging with Apache Kafka
package com.example.demo.controller;
import com.example.demo.dto.FileMetadata;
import com.example.demo.service.FileStorageService;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
File upload and download handling
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
username VARCHAR(100) NOT NULL UNIQUE,
email VARCHAR(255) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
Database migration with Flyway
Share this code
Here's the card — post it anywhere.