google-site-verification: google61fe8ba583a51912.html
Circuit Breaker with Resilience4j in Java

Introduction

Circuit Breaker is a design pattern that prevents cascading failures in distributed systems. Resilience4j is a lightweight fault tolerance library inspired by Netflix Hystrix, providing circuit breaker, rate limiter, retry, bulkhead, and time limiter patterns.

Core Concepts

Circuit Breaker States

// Three states: CLOSED -> Normal operation, requests pass through OPEN -> Short-circuited, requests fail fast HALF_OPEN -> Testing if underlying service has recovered

Setup and Dependencies

Maven Dependencies

<dependencies> <!-- Resilience4j Core --> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-circuitbreaker</artifactId> <version>2.1.0</version> </dependency> <!-- Spring Boot Integration --> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-spring-boot2</artifactId> <version>2.1.0</version> </dependency> <!-- Micrometer Metrics --> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-micrometer</artifactId> <version>2.1.0</version> </dependency> <!-- Reactor Support --> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-reactor</artifactId> <version>2.1.0</version> </dependency> <!-- Retrofit Support --> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-retrofit</artifactId> <version>2.1.0</version> </dependency> </dependencies>

Basic Circuit Breaker Usage

Manual Circuit Breaker Configuration

@Component public class BasicCircuitBreakerService { private final CircuitBreakerRegistry circuitBreakerRegistry; private final ExternalService externalService; public BasicCircuitBreakerService(CircuitBreakerRegistry circuitBreakerRegistry, ExternalService externalService) { this.circuitBreakerRegistry = circuitBreakerRegistry; this.externalService = externalService; } public void demonstrateBasicUsage() { // Create circuit breaker configuration CircuitBreakerConfig config = CircuitBreakerConfig.custom() .failureRateThreshold(50) // Open circuit if 50% of calls fail .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.COUNT_BASED) .slidingWindowSize(10) // Last 10 calls are considered .minimumNumberOfCalls(5) // Minimum calls before calculating error rate .waitDurationInOpenState(Duration.ofSeconds(10)) // Time in OPEN state before trying HALF_OPEN .permittedNumberOfCallsInHalfOpenState(3) // Number of calls in HALF_OPEN state .recordExceptions(IOException.class, TimeoutException.class) // Exceptions to record as failures .ignoreExceptions(BusinessException.class) // Exceptions to ignore .build(); // Create circuit breaker instance CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("externalService", config); // Decorate the call Supplier<String> decoratedSupplier = CircuitBreaker.decorateSupplier( circuitBreaker, externalService::callExternalService ); try { String result = decoratedSupplier.get(); System.out.println("Success: " + result); } catch (CallNotPermittedException e) { System.out.println("Circuit breaker is OPEN - call blocked"); } catch (Exception e) { System.out.println("Call failed: " + e.getMessage()); } } // Using Try.of with circuit breaker public String getDataWithFallback(String id) { return Try.ofSupplier( CircuitBreaker.decorateSupplier( circuitBreakerRegistry.circuitBreaker("dataService"), () -> externalService.fetchData(id) ) ).recover(throwable -> { // Fallback logic return getCachedData(id).orElse("default-value"); }).get(); } } // Example external service @Service class ExternalService { public String callExternalService() { // Simulate external service call if (Math.random() > 0.7) { throw new RuntimeException("Service unavailable"); } return "Success response"; } public String fetchData(String id) { // Simulate data fetch return "Data for " + id; } }

Advanced Circuit Breaker Configuration

Comprehensive Configuration

@Configuration public class CircuitBreakerConfiguration { @Bean public CircuitBreakerConfig defaultCircuitBreakerConfig() { return CircuitBreakerConfig.custom() .failureRateThreshold(50) // Percentage of failures to trigger OPEN state .slowCallRateThreshold(50) // Percentage of slow calls to trigger OPEN .slowCallDurationThreshold(Duration.ofSeconds(2)) // What constitutes a slow call .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.TIME_BASED) .slidingWindowSize(10) // Number of calls for COUNT_BASED, seconds for TIME_BASED .minimumNumberOfCalls(10) // Minimum calls before calculating error rate .waitDurationInOpenState(Duration.ofSeconds(30)) .permittedNumberOfCallsInHalfOpenState(5) .recordExceptions(IOException.class, TimeoutException.class, CallNotPermittedException.class) .ignoreExceptions(BusinessException.class, ValidationException.class) .automaticTransitionFromOpenToHalfOpenEnabled(true) .writableStackTraceEnabled(false) // Disable stack traces for performance .build(); } @Bean public CircuitBreakerConfig strictCircuitBreakerConfig() { return CircuitBreakerConfig.custom() .failureRateThreshold(20) // More sensitive - opens at 20% failure rate .slidingWindowSize(20) .minimumNumberOfCalls(5) .waitDurationInOpenState(Duration.ofMinutes(1)) .permittedNumberOfCallsInHalfOpenState(2) .recordExceptions(Exception.class) // Record all exceptions .build(); } @Bean public CircuitBreakerConfig lenientCircuitBreakerConfig() { return CircuitBreakerConfig.custom() .failureRateThreshold(80) // Less sensitive - opens at 80% failure rate .slidingWindowSize(50) .minimumNumberOfCalls(20) .waitDurationInOpenState(Duration.ofSeconds(10)) .permittedNumberOfCallsInHalfOpenState(10) .recordExceptions(IOException.class, TimeoutException.class) .ignoreExceptions(BusinessException.class) .build(); } @Bean public CircuitBreakerRegistry circuitBreakerRegistry(CircuitBreakerConfig defaultConfig) { return CircuitBreakerRegistry.of(defaultConfig); } @Bean public CircuitBreakerEventPublisher circuitBreakerEventPublisher() { return new CircuitBreakerEventPublisher(); } }

Spring Boot Integration

Application Configuration

# application.yml resilience4j: circuitbreaker: configs: default: slidingWindowSize: 100 failureRateThreshold: 50 waitDurationInOpenState: 10s permittedNumberOfCallsInHalfOpenState: 10 minimumNumberOfCalls: 10 slidingWindowType: COUNT_BASED recordExceptions: - org.springframework.web.client.HttpServerErrorException - java.io.IOException - java.util.concurrent.TimeoutException ignoreExceptions: - com.example.BusinessException strict: failureRateThreshold: 20 waitDurationInOpenState: 60s slidingWindowSize: 50 lenient: failureRateThreshold: 80 waitDurationInOpenState: 5s instances: userService: baseConfig: default failureRateThreshold: 30 paymentService: baseConfig: strict waitDurationInOpenState: 30s externalApi: baseConfig: lenient slidingWindowSize: 200 management: endpoints: web: exposure: include: health,metrics,circuitbreakers endpoint: circuitbreakers: enabled: true metrics: export: prometheus: enabled: true

Annotation-Based Circuit Breaker

@Service public class AnnotatedCircuitBreakerService { private final ExternalApiClient externalApiClient; private final CacheService cacheService; public AnnotatedCircuitBreakerService(ExternalApiClient externalApiClient, CacheService cacheService) { this.externalApiClient = externalApiClient; this.cacheService = cacheService; } @CircuitBreaker(name = "userService", fallbackMethod = "getUserFallback") public User getUser(String userId) { return externalApiClient.getUser(userId); } @CircuitBreaker(name = "paymentService", fallbackMethod = "processPaymentFallback") public PaymentResult processPayment(PaymentRequest request) { return externalApiClient.processPayment(request); } @CircuitBreaker(name = "externalApi", fallbackMethod = "searchFallback") public SearchResult search(String query, int page) { return externalApiClient.search(query, page); } @CircuitBreaker(name = "cacheService", fallbackMethod = "cacheFallback") @RateLimiter(name = "cacheService") @Retry(name = "cacheService", fallbackMethod = "cacheFallback") @Bulkhead(name = "cacheService") public String getFromCache(String key) { return cacheService.get(key); } // Fallback methods private User getUserFallback(String userId, Exception e) { log.warn("Circuit breaker fallback for getUser: {}", e.getMessage()); return User.builder() .id(userId) .name("Fallback User") .email("[email protected]") .build(); } private PaymentResult processPaymentFallback(PaymentRequest request, Exception e) { log.error("Payment processing failed, queuing for retry", e); return PaymentResult.builder() .status("PENDING") .message("Payment queued for processing") .build(); } private SearchResult searchFallback(String query, int page, Exception e) { log.warn("Search fallback for query: {}", query); return SearchResult.builder() .query(query) .results(Collections.emptyList()) .total(0) .fallback(true) .build(); } private String cacheFallback(String key, Exception e) { log.warn("Cache fallback for key: {}", key); return "default-value"; } } // Supporting classes @Data @Builder class User { private String id; private String name; private String email; } @Data @Builder class PaymentResult { private String status; private String message; } @Data class PaymentRequest { private String amount; private String currency; private String cardToken; } @Data @Builder class SearchResult { private String query; private List<String> results; private int total; private boolean fallback; }

Reactive Circuit Breaker

Reactor Integration

@Service public class ReactiveCircuitBreakerService { private final CircuitBreakerRegistry circuitBreakerRegistry; private final ReactiveExternalService reactiveExternalService; public ReactiveCircuitBreakerService(CircuitBreakerRegistry circuitBreakerRegistry, ReactiveExternalService reactiveExternalService) { this.circuitBreakerRegistry = circuitBreakerRegistry; this.reactiveExternalService = reactiveExternalService; } public Mono<String> getDataReactive(String id) { CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("reactiveService"); return CircuitBreakerOperator.of(circuitBreaker) .apply(reactiveExternalService.fetchData(id)) .onErrorResume(throwable -> { if (throwable instanceof CallNotPermittedException) { return Mono.just("Circuit breaker is OPEN - fallback response"); } return Mono.just("Error fallback: " + throwable.getMessage()); }); } public Flux<String> streamDataReactive(String query) { CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("streamService"); return Flux.fromStream(IntStream.range(0, 10).boxed()) .flatMap(i -> CircuitBreakerOperator.of(circuitBreaker) .apply(reactiveExternalService.getChunk(query, i)) .onErrorResume(throwable -> Mono.just("Fallback chunk " + i)) ); } // Using transformDeferred for more control public Mono<User> getUserReactive(String userId) { return reactiveExternalService.getUser(userId) .transformDeferred(CircuitBreakerOperator.of( circuitBreakerRegistry.circuitBreaker("userServiceReactive") )) .onErrorResume(this::handleUserServiceError); } private Mono<User> handleUserServiceError(Throwable throwable) { if (throwable instanceof CallNotPermittedException) { return Mono.just(createFallbackUser()); } log.error("Error fetching user", throwable); return Mono.error(throwable); } private User createFallbackUser() { return User.builder() .id("fallback") .name("Fallback User") .email("[email protected]") .build(); } } @Service class ReactiveExternalService { public Mono<String> fetchData(String id) { return Mono.fromCallable(() -> { // Simulate external call if (Math.random() > 0.8) { throw new RuntimeException("Service unavailable"); } return "Data for " + id; }).subscribeOn(Schedulers.boundedElastic()); } public Mono<String> getChunk(String query, int index) { return Mono.just("Chunk " + index + " for " + query) .delayElement(Duration.ofMillis(100)); } public Mono<User> getUser(String userId) { return Mono.fromCallable(() -> { // Simulate user service call return User.builder() .id(userId) .name("Real User") .email("[email protected]") .build(); }).subscribeOn(Schedulers.boundedElastic()); } }

Event Handling and Monitoring

Circuit Breaker Events

@Component public class CircuitBreakerEventListener { private static final Logger logger = LoggerFactory.getLogger(CircuitBreakerEventListener.class); private final MeterRegistry meterRegistry; public CircuitBreakerEventListener(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; } @EventListener public void onCircuitBreakerEvent(CircuitBreakerOnStateTransitionEvent event) { logger.info("Circuit Breaker {} transitioned from {} to {}", event.getCircuitBreakerName(), event.getStateTransition().getFromState(), event.getStateTransition().getToState()); // Record metrics for state transitions Counter.builder("circuitbreaker.state.transitions") .tag("name", event.getCircuitBreakerName()) .tag("from", event.getStateTransition().getFromState().name()) .tag("to", event.getStateTransition().getToState().name()) .register(meterRegistry) .increment(); } @EventListener public void onCircuitBreakerCallEvent(CircuitBreakerOnCallNotPermittedEvent event) { logger.warn("Circuit Breaker {} is OPEN - call not permitted for {}", event.getCircuitBreakerName(), event.getEventType()); Counter.builder("circuitbreaker.calls.blocked") .tag("name", event.getCircuitBreakerName()) .register(meterRegistry) .increment(); } @EventListener public void onCircuitBreakerErrorEvent(CircuitBreakerOnErrorEvent event) { logger.error("Circuit Breaker {} recorded error: {}", event.getCircuitBreakerName(), event.getThrowable().getMessage()); Counter.builder("circuitbreaker.calls.failed") .tag("name", event.getCircuitBreakerName()) .tag("error", event.getThrowable().getClass().getSimpleName()) .register(meterRegistry) .increment(); } @EventListener public void onCircuitBreakerSuccessEvent(CircuitBreakerOnSuccessEvent event) { logger.debug("Circuit Breaker {} recorded successful call", event.getCircuitBreakerName()); Counter.builder("circuitbreaker.calls.successful") .tag("name", event.getCircuitBreakerName()) .register(meterRegistry) .increment(); } @EventListener public void onCircuitBreakerSlowCallEvent(CircuitBreakerOnSlowCallRateEvent event) { logger.warn("Circuit Breaker {} detected slow call rate", event.getCircuitBreakerName()); Counter.builder("circuitbreaker.slow.calls") .tag("name", event.getCircuitBreakerName()) .register(meterRegistry) .increment(); } } // Custom event publisher @Component public class CircuitBreakerEventPublisher { private final CircuitBreakerRegistry circuitBreakerRegistry; public CircuitBreakerEventPublisher(CircuitBreakerRegistry circuitBreakerRegistry) { this.circuitBreakerRegistry = circuitBreakerRegistry; registerEventConsumers(); } private void registerEventConsumers() { circuitBreakerRegistry.getAllCircuitBreakers().forEach((name, circuitBreaker) -> { circuitBreaker.getEventPublisher() .onStateTransition(this::onStateTransition) .onCallNotPermitted(this::onCallNotPermitted) .onError(this::onError) .onSuccess(this::onSuccess) .onSlowCallRate(this::onSlowCallRate) .onFailureRate(this::onFailureRate); }); } private void onStateTransition(CircuitBreakerOnStateTransitionEvent event) { // Publish to message queue or external monitoring System.out.printf("State Transition: %s from %s to %s%n", event.getCircuitBreakerName(), event.getStateTransition().getFromState(), event.getStateTransition().getToState()); } private void onCallNotPermitted(CircuitBreakerOnCallNotPermittedEvent event) { System.out.printf("Call Not Permitted: %s%n", event.getCircuitBreakerName()); } private void onError(CircuitBreakerOnErrorEvent event) { System.out.printf("Error in %s: %s%n", event.getCircuitBreakerName(), event.getThrowable().getMessage()); } private void onSuccess(CircuitBreakerOnSuccessEvent event) { System.out.printf("Success in %s%n", event.getCircuitBreakerName()); } private void onSlowCallRate(CircuitBreakerOnSlowCallRateEvent event) { System.out.printf("Slow call rate in %s%n", event.getCircuitBreakerName()); } private void onFailureRate(CircuitBreakerOnFailureRateEvent event) { System.out.printf("Failure rate exceeded in %s%n", event.getCircuitBreakerName()); } }

Advanced Patterns

Composite Circuit Breaker

@Service public class CompositeCircuitBreakerService { private final CircuitBreakerRegistry circuitBreakerRegistry; private final Map<String, ExternalService> services; public CompositeCircuitBreakerService(CircuitBreakerRegistry circuitBreakerRegistry) { this.circuitBreakerRegistry = circuitBreakerRegistry; this.services = initializeServices(); } public String callWithCompositeCircuitBreaker(String serviceName, String operation) { CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker(serviceName); if (!circuitBreaker.tryAcquirePermission()) { throw new CallNotPermittedException("Circuit breaker is OPEN for " + serviceName); } long start = System.nanoTime(); try { String result = services.get(serviceName).execute(operation); circuitBreaker.onSuccess(System.nanoTime() - start, TimeUnit.NANOSECONDS); return result; } catch (Exception e) { circuitBreaker.onError(System.nanoTime() - start, TimeUnit.NANOSECONDS, e); throw e; } } public <T> T executeWithMetrics(String serviceName, Supplier<T> operation) { CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker(serviceName); return circuitBreaker.executeSupplier(() -> { Timer.Sample sample = Timer.start(); try { T result = operation.get(); sample.stop(Timer.builder("circuitbreaker.operation.duration") .tag("service", serviceName) .tag("status", "success") .register(meterRegistry)); return result; } catch (Exception e) { sample.stop(Timer.builder("circuitbreaker.operation.duration") .tag("service", serviceName) .tag("status", "error") .register(meterRegistry)); throw e; } }); } private Map<String, ExternalService> initializeServices() { Map<String, ExternalService> services = new HashMap<>(); services.put("userService", new UserService()); services.put("paymentService", new PaymentService()); services.put("inventoryService", new InventoryService()); return services; } } // Circuit Breaker with custom predicate @Service class CustomCircuitBreakerService { public String callWithCustomFailurePredicate(String input) { CircuitBreakerConfig config = CircuitBreakerConfig.custom() .failureRateThreshold(50) .slidingWindowSize(10) .recordException(throwable -> throwable instanceof IOException || throwable instanceof TimeoutException || (throwable instanceof RuntimeException && throwable.getMessage().contains("unavailable"))) .build(); CircuitBreaker circuitBreaker = CircuitBreaker.of("customService", config); return circuitBreaker.executeSupplier(() -> { if (input.equals("fail")) { throw new RuntimeException("Service unavailable"); } return "Success: " + input; }); } }

Integration with HTTP Clients

RestTemplate Integration

@Configuration public class RestTemplateCircuitBreakerConfig { @Bean public RestTemplate restTemplate(CircuitBreakerRegistry circuitBreakerRegistry) { RestTemplate restTemplate = new RestTemplate(); // Add circuit breaker interceptor List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>(); interceptors.add(circuitBreakerInterceptor(circuitBreakerRegistry)); restTemplate.setInterceptors(interceptors); return restTemplate; } @Bean public ClientHttpRequestInterceptor circuitBreakerInterceptor(CircuitBreakerRegistry registry) { return (request, body, execution) -> { String serviceName = extractServiceName(request.getURI()); CircuitBreaker circuitBreaker = registry.circuitBreaker(serviceName); return circuitBreaker.executeSupplier(() -> { try { ClientHttpResponse response = execution.execute(request, body); if (response.getStatusCode().is5xxServerError()) { throw new HttpClientErrorException(response.getStatusCode(), "Server error: " + response.getStatusText()); } return response; } catch (Exception e) { throw new RuntimeException("HTTP call failed", e); } }); }; } private String extractServiceName(URI uri) { // Extract service name from URI return uri.getHost(); // or use service discovery } } // Feign Client Integration @FeignClient(name = "user-service", configuration = FeignConfig.class) public interface UserServiceClient { @CircuitBreaker(name = "userService") @GetMapping("/users/{id}") User getUser(@PathVariable String id); @CircuitBreaker(name = "userService") @PostMapping("/users") User createUser(@RequestBody User user); } @Configuration public class FeignConfig { @Bean public CircuitBreaker feignCircuitBreaker(CircuitBreakerRegistry registry) { return registry.circuitBreaker("feignClient"); } }

Testing Circuit Breakers

Comprehensive Testing

@SpringBootTest @ExtendWith(SpringExtension.class) class CircuitBreakerTest { @Autowired private CircuitBreakerRegistry circuitBreakerRegistry; @Autowired private AnnotatedCircuitBreakerService circuitBreakerService; @Mock private ExternalApiClient externalApiClient; @Test void testCircuitBreakerStateTransitions() { // Given CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("testService"); // When - simulate failures to trigger OPEN state for (int i = 0; i < 10; i++) { try { circuitBreaker.executeRunnable(() -> { throw new RuntimeException("Simulated failure"); }); } catch (Exception e) { // Expected } } // Then assertThat(circuitBreaker.getState()).isEqualTo(CircuitBreaker.State.OPEN); } @Test void testFallbackMethod() { // Given when(externalApiClient.getUser("123")) .thenThrow(new RuntimeException("Service unavailable")); // When User result = circuitBreakerService.getUser("123"); // Then assertThat(result.getName()).isEqualTo("Fallback User"); assertThat(result.getEmail()).isEqualTo("[email protected]"); } @Test void testCallNotPermittedException() { // Given CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("testService"); // Force circuit breaker to OPEN state circuitBreaker.transitionToOpenState(); // When/Then assertThatThrownBy(() -> circuitBreaker.executeRunnable(() -> {})) .isInstanceOf(CallNotPermittedException.class); } @Test void testCircuitBreakerMetrics() { // Given CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("metricsTest"); // When - execute some calls for (int i = 0; i < 5; i++) { try { circuitBreaker.executeSupplier(() -> "Success"); } catch (Exception e) { // Ignore } } // Then CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics(); assertThat(metrics.getNumberOfSuccessfulCalls()).isGreaterThan(0); } } // Test configuration @TestConfiguration public class TestCircuitBreakerConfig { @Bean public CircuitBreakerRegistry circuitBreakerRegistry() { CircuitBreakerConfig config = CircuitBreakerConfig.custom() .slidingWindowSize(5) .minimumNumberOfCalls(2) .waitDurationInOpenState(Duration.ofSeconds(1)) .build(); return CircuitBreakerRegistry.of(config); } }

Best Practices

Production Configuration

@Component public class CircuitBreakerBestPractices { private final CircuitBreakerRegistry circuitBreakerRegistry; public CircuitBreakerBestPractices(CircuitBreakerRegistry circuitBreakerRegistry) { this.circuitBreakerRegistry = circuitBreakerRegistry; } // 1. Use meaningful names for circuit breakers public void useMeaningfulNames() { // Good CircuitBreaker userServiceCircuitBreaker = circuitBreakerRegistry.circuitBreaker("userService"); CircuitBreaker paymentServiceCircuitBreaker = circuitBreakerRegistry.circuitBreaker("paymentService"); // Avoid CircuitBreaker cb1 = circuitBreakerRegistry.circuitBreaker("cb1"); } // 2. Configure appropriate thresholds public void configureAppropriateThresholds() { CircuitBreakerConfig config = CircuitBreakerConfig.custom() .failureRateThreshold(50) // Adjust based on service criticality .slowCallRateThreshold(80) // For latency-sensitive services .waitDurationInOpenState(Duration.ofSeconds(30)) // Balance between recovery and protection .minimumNumberOfCalls(10) // Ensure statistical significance .build(); } // 3. Use proper exception handling public void handleExceptionsProperly() { CircuitBreakerConfig config = CircuitBreakerConfig.custom() .recordExceptions(IOException.class, TimeoutException.class) // Network-related exceptions .ignoreExceptions(BusinessException.class, ValidationException.class) // Business logic exceptions .build(); } // 4. Implement meaningful fallbacks public String implementMeaningfulFallback(String input, Exception e) { if (e instanceof CallNotPermittedException) { return "Service temporarily unavailable - please try again later"; } if (e instanceof TimeoutException) { return "Request timed out - please try again"; } // Return cached data, default values, or queue for retry return getCachedValue(input).orElse("Default value"); } // 5. Monitor and adjust configurations public void monitorAndAdjust() { CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("monitoredService"); // Regularly check metrics and adjust configuration if needed CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics(); double failureRate = metrics.getFailureRate(); if (failureRate > 70) { // Consider tightening the circuit breaker log.warn("High failure rate detected for service: {}", failureRate); } } private Optional<String> getCachedValue(String key) { // Implementation for cache retrieval return Optional.empty(); } }

Conclusion

Resilience4j Circuit Breaker provides robust fault tolerance for Java applications:

  • Lightweight - No external dependencies required
  • Flexible configuration - Customizable for different services
  • Spring Boot integration - Seamless integration with Spring ecosystem
  • Reactive support - Works with Reactor and other reactive libraries
  • Comprehensive monitoring - Events and metrics for observability

Key benefits:

  • Prevents cascading failures by isolating faulty services
  • Improves system resilience with automatic recovery
  • Provides meaningful fallbacks for graceful degradation
  • Enables monitoring with detailed metrics and events

By implementing circuit breakers with Resilience4j, you can build more resilient and fault-tolerant microservices architectures that gracefully handle failures and maintain system stability.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper