Created
August 27, 2025 07:48
-
-
Save valarpirai/d340b9a0a6a04a2ec4d3f34f96c40eca to your computer and use it in GitHub Desktop.
Java Fault Tolerance - https://github.com/resilience4j/resilience4j
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| resilience4j: | |
| circuitbreaker: | |
| instances: | |
| paymentService: | |
| slidingWindowSize: 10 | |
| failureRateThreshold: 50 | |
| slowCallRateThreshold: 100 | |
| slowCallDurationThreshold: 2000ms | |
| permittedNumberOfCallsInHalfOpenState: 3 | |
| waitDurationInOpenState: 30s | |
| recordExceptions: | |
| - java.io.IOException | |
| - org.springframework.web.client.HttpServerErrorException | |
| retry: | |
| instances: | |
| paymentService: | |
| maxAttempts: 3 | |
| waitDuration: 500ms | |
| enableExponentialBackoff: true | |
| exponentialBackoffMultiplier: 2 | |
| retryExceptions: | |
| - java.io.IOException | |
| - org.springframework.web.client.HttpServerErrorException | |
| timelimiter: | |
| instances: | |
| paymentService: | |
| timeoutDuration: 1500ms | |
| cancelRunningFuture: true | |
| bulkhead: | |
| instances: | |
| paymentService: | |
| maxConcurrentCalls: 10 | |
| maxWaitDuration: 500ms |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <dependencies> | |
| <!-- Core modules --> | |
| <dependency> | |
| <groupId>io.github.resilience4j</groupId> | |
| <artifactId>resilience4j-circuitbreaker</artifactId> | |
| <version>2.2.0</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>io.github.resilience4j</groupId> | |
| <artifactId>resilience4j-retry</artifactId> | |
| <version>2.2.0</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>io.github.resilience4j</groupId> | |
| <artifactId>resilience4j-timelimiter</artifactId> | |
| <version>2.2.0</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>io.github.resilience4j</groupId> | |
| <artifactId>resilience4j-bulkhead</artifactId> | |
| <version>2.2.0</version> | |
| </dependency> | |
| <!-- Spring Boot integration --> | |
| <dependency> | |
| <groupId>io.github.resilience4j</groupId> | |
| <artifactId>resilience4j-spring-boot3</artifactId> | |
| <version>2.2.0</version> | |
| </dependency> | |
| <!-- Metrics --> | |
| <dependency> | |
| <groupId>io.github.resilience4j</groupId> | |
| <artifactId>resilience4j-micrometer</artifactId> | |
| <version>2.2.0</version> | |
| </dependency> | |
| </dependencies> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import io.github.resilience4j.bulkhead.Bulkhead; | |
| import io.github.resilience4j.bulkhead.BulkheadConfig; | |
| import io.github.resilience4j.bulkhead.BulkheadRegistry; | |
| import io.github.resilience4j.circuitbreaker.CircuitBreaker; | |
| import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig; | |
| import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry; | |
| import io.github.resilience4j.retry.Retry; | |
| import io.github.resilience4j.retry.RetryConfig; | |
| import io.github.resilience4j.retry.RetryRegistry; | |
| import io.github.resilience4j.timelimiter.TimeLimiter; | |
| import io.github.resilience4j.timelimiter.TimeLimiterConfig; | |
| import io.github.resilience4j.timelimiter.TimeLimiterRegistry; | |
| import io.vavr.control.Try; | |
| import java.time.Duration; | |
| import java.util.concurrent.Executors; | |
| import java.util.function.Supplier; | |
| public class FaultToleranceDemo { | |
| public static void main(String[] args) { | |
| // Configurations | |
| CircuitBreakerConfig cbConfig = CircuitBreakerConfig.custom() | |
| .slidingWindowSize(5) | |
| .failureRateThreshold(50) | |
| .waitDurationInOpenState(Duration.ofSeconds(5)) | |
| .permittedNumberOfCallsInHalfOpenState(2) | |
| .build(); | |
| RetryConfig retryConfig = RetryConfig.custom() | |
| .maxAttempts(3) | |
| .waitDuration(Duration.ofMillis(500)) | |
| .enableExponentialBackoff(true) | |
| .exponentialBackoffMultiplier(2) | |
| .build(); | |
| TimeLimiterConfig tlConfig = TimeLimiterConfig.custom() | |
| .timeoutDuration(Duration.ofSeconds(1)) | |
| .build(); | |
| BulkheadConfig bhConfig = BulkheadConfig.custom() | |
| .maxConcurrentCalls(2) | |
| .maxWaitDuration(Duration.ofMillis(500)) | |
| .build(); | |
| // Registries | |
| CircuitBreakerRegistry cbRegistry = CircuitBreakerRegistry.of(cbConfig); | |
| RetryRegistry retryRegistry = RetryRegistry.of(retryConfig); | |
| TimeLimiterRegistry tlRegistry = TimeLimiterRegistry.of(tlConfig); | |
| BulkheadRegistry bhRegistry = BulkheadRegistry.of(bhConfig); | |
| CircuitBreaker circuitBreaker = cbRegistry.circuitBreaker("demo"); | |
| Retry retry = retryRegistry.retry("demo"); | |
| TimeLimiter timeLimiter = tlRegistry.timeLimiter("demo"); | |
| Bulkhead bulkhead = bhRegistry.bulkhead("demo"); | |
| // Simulate flaky service | |
| Supplier<String> flakyService = () -> { | |
| double failureRate = Math.random(); | |
| if (failureRate > 0.6) { | |
| throw new RuntimeException("Service failed!"); | |
| } | |
| try { | |
| Thread.sleep((long) (Math.random() * 1200)); // Random delay | |
| } catch (InterruptedException e) { | |
| Thread.currentThread().interrupt(); | |
| } | |
| return "Success!"; | |
| }; | |
| // Decorate | |
| Supplier<String> decorated = Bulkhead.decorateSupplier(bulkhead, | |
| TimeLimiter.decorateFutureSupplier(timeLimiter, | |
| Retry.decorateSupplier(retry, | |
| CircuitBreaker.decorateSupplier(circuitBreaker, flakyService)))); | |
| // Simulate 20 calls | |
| for (int i = 1; i <= 20; i++) { | |
| String result = Try.ofSupplier(decorated) | |
| .recover(throwable -> "Fallback: Try later") | |
| .get(); | |
| System.out.println("Call " + i + ": " + result + " | CB State: " + circuitBreaker.getState()); | |
| // Simulate time for cooldown | |
| if (circuitBreaker.getState() == CircuitBreaker.State.OPEN) { | |
| try { | |
| Thread.sleep(6000); | |
| } catch (InterruptedException e) { | |
| Thread.currentThread().interrupt(); | |
| } | |
| } | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import io.github.resilience4j.bulkhead.Bulkhead; | |
| import io.github.resilience4j.bulkhead.BulkheadRegistry; | |
| import io.github.resilience4j.circuitbreaker.CircuitBreaker; | |
| import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry; | |
| import io.github.resilience4j.retry.Retry; | |
| import io.github.resilience4j.retry.RetryRegistry; | |
| import io.github.resilience4j.timelimiter.TimeLimiter; | |
| import io.github.resilience4j.timelimiter.TimeLimiterRegistry; | |
| import io.vavr.control.Try; | |
| import org.springframework.stereotype.Service; | |
| import org.springframework.web.client.RestTemplate; | |
| import java.util.function.Supplier; | |
| @Service | |
| public class PaymentService { | |
| private final RestTemplate restTemplate; | |
| private final CircuitBreaker circuitBreaker; | |
| private final Retry retry; | |
| private final TimeLimiter timeLimiter; | |
| private final Bulkhead bulkhead; | |
| public PaymentService(RestTemplate restTemplate, CircuitBreakerRegistry cbRegistry, | |
| RetryRegistry retryRegistry, TimeLimiterRegistry tlRegistry, | |
| BulkheadRegistry bhRegistry) { | |
| this.restTemplate = restTemplate; | |
| this.circuitBreaker = cbRegistry.circuitBreaker("paymentService"); | |
| this.retry = retryRegistry.retry("paymentService"); | |
| this.timeLimiter = tlRegistry.timeLimiter("paymentService"); | |
| this.bulkhead = bhRegistry.bulkhead("paymentService"); | |
| } | |
| public String processPayment(String orderId) { | |
| // Wrap REST call in all patterns | |
| Supplier<String> supplier = () -> restTemplate.postForObject( | |
| "http://payment-service/pay", orderId, String.class); | |
| // Decorate with patterns (order matters!) | |
| Supplier<String> decorated = Bulkhead.decorateSupplier(bulkhead, | |
| TimeLimiter.decorateFutureSupplier(timeLimiter, | |
| Retry.decorateSupplier(retry, | |
| CircuitBreaker.decorateSupplier(circuitBreaker, supplier)))); | |
| return Try.ofSupplier(decorated) | |
| .recover(throwable -> fallback(orderId, throwable)) | |
| .getOrElseThrow(ex -> new RuntimeException("Payment failed", ex)); | |
| } | |
| private String fallback(String orderId, Throwable t) { | |
| System.err.println("Fallback triggered for order " + orderId + ": " + t.getMessage()); | |
| return "Payment delayed - try again later"; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment