Skip to content

Instantly share code, notes, and snippets.

@valarpirai
Created August 27, 2025 07:48
Show Gist options
  • Save valarpirai/d340b9a0a6a04a2ec4d3f34f96c40eca to your computer and use it in GitHub Desktop.
Save valarpirai/d340b9a0a6a04a2ec4d3f34f96c40eca to your computer and use it in GitHub Desktop.
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
<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>
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();
}
}
}
}
}
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