Build fault-tolerant network services
—
Circuit breaker patterns that prevent cascading failures by monitoring failure rates and temporarily blocking calls to failing services. Provides automatic failure detection, recovery mechanisms, and named circuit breaker instances for shared state.
Standard circuit breaker functionality with configurable failure thresholds, delays, and recovery logic.
@CircuitBreaker(
requestVolumeThreshold = 20,
failureRatio = 0.5,
delay = 5000,
delayUnit = ChronoUnit.MILLISECONDS,
successThreshold = 1,
failOn = {IOException.class, TimeoutException.class},
skipOn = {IllegalArgumentException.class}
)
public ReturnType protectedMethod() throws Exception;requestVolumeThreshold - Minimum requests before failure evaluation (default: 20)failureRatio - Failure ratio to open circuit (0.0-1.0, default: 0.5)delay - Time before transitioning from open to half-open (default: 5 seconds)delayUnit - Time unit for delay (default: MILLIS)successThreshold - Successful calls needed to close from half-open (default: 1)failOn - Exception types considered failures (default: Throwable.class)skipOn - Exception types not considered failures (takes precedence)@ApplicationScoped
public class PaymentService {
// Payment processing with circuit breaker
@CircuitBreaker(
requestVolumeThreshold = 10,
failureRatio = 0.3,
delay = 30000,
successThreshold = 3
)
@Fallback(fallbackMethod = "processPaymentOffline")
public PaymentResult processPayment(PaymentRequest request) throws PaymentException {
return paymentGateway.process(request);
}
public PaymentResult processPaymentOffline(PaymentRequest request) {
// Queue payment for later processing
return paymentQueue.enqueue(request);
}
// External service with aggressive circuit breaker
@CircuitBreaker(
requestVolumeThreshold = 5,
failureRatio = 0.2,
delay = 60000,
failOn = {ConnectException.class, SocketTimeoutException.class},
skipOn = {ValidationException.class}
)
public ExternalApiResponse callExternalService(ApiRequest request) {
return externalApiClient.call(request);
}
}Named circuit breaker instances that share state across multiple methods or classes.
@CircuitBreakerName("shared-circuit-breaker")
@CircuitBreaker(requestVolumeThreshold = 10, failureRatio = 0.4)
public ReturnType namedCircuitBreakerMethod();
// Multiple methods sharing the same circuit breaker state
@CircuitBreakerName("database-circuit")
public ReturnType firstDatabaseMethod();
@CircuitBreakerName("database-circuit")
public ReturnType secondDatabaseMethod();@ApplicationScoped
public class DatabaseService {
// All database operations share the same circuit breaker
@CircuitBreakerName("database-operations")
@CircuitBreaker(requestVolumeThreshold = 15, failureRatio = 0.3)
public List<User> findUsers(UserQuery query) throws SQLException {
return userRepository.find(query);
}
@CircuitBreakerName("database-operations")
@CircuitBreaker(requestVolumeThreshold = 15, failureRatio = 0.3)
public void saveUser(User user) throws SQLException {
userRepository.save(user);
}
@CircuitBreakerName("database-operations")
@CircuitBreaker(requestVolumeThreshold = 15, failureRatio = 0.3)
public void deleteUser(Long userId) throws SQLException {
userRepository.delete(userId);
}
}
@ApplicationScoped
public class OrderService {
// Order service also uses the same database circuit breaker
@CircuitBreakerName("database-operations")
@CircuitBreaker(requestVolumeThreshold = 15, failureRatio = 0.3)
public List<Order> findOrders(OrderQuery query) throws SQLException {
return orderRepository.find(query);
}
}Combined circuit breaker and fallback patterns for complete resilience.
@CircuitBreaker(requestVolumeThreshold = 10, failureRatio = 0.5)
@Fallback(fallbackMethod = "fallbackMethod")
public ReturnType protectedMethodWithFallback();
@CircuitBreaker(requestVolumeThreshold = 5)
@Fallback(value = CustomFallbackHandler.class)
public ReturnType protectedMethodWithHandler();@ApplicationScoped
public class WeatherService {
@Inject
CacheService cache;
// Weather API with circuit breaker and cached fallback
@CircuitBreaker(
requestVolumeThreshold = 8,
failureRatio = 0.4,
delay = 20000
)
@Fallback(fallbackMethod = "getCachedWeather")
@Timeout(5000)
public WeatherData getCurrentWeather(String city) throws WeatherServiceException {
return weatherApiClient.getWeather(city);
}
public WeatherData getCachedWeather(String city) {
WeatherData cached = cache.get("weather:" + city);
if (cached != null) {
return cached.withStaleIndicator();
}
return WeatherData.unavailable(city);
}
// Stock quote service with handler-based fallback
@CircuitBreaker(requestVolumeThreshold = 5, failureRatio = 0.6)
@Fallback(value = StockQuoteFallbackHandler.class)
public StockQuote getStockQuote(String symbol) throws QuoteServiceException {
return stockApiClient.getQuote(symbol);
}
}
public class StockQuoteFallbackHandler implements FallbackHandler<StockQuote> {
@Inject
HistoricalDataService historicalData;
@Override
public StockQuote handle(ExecutionContext context) {
String symbol = (String) context.getParameters()[0];
// Return last known quote or estimated quote
return historicalData.getLastKnownQuote(symbol)
.orElse(StockQuote.estimated(symbol));
}
}Integration with metrics and health checks for circuit breaker monitoring.
// Circuit breaker with custom name for monitoring
@CircuitBreakerName("payment-gateway")
@CircuitBreaker(requestVolumeThreshold = 20, failureRatio = 0.25)
public PaymentResult processPayment(PaymentRequest request);
// Accessing circuit breaker state programmatically
CircuitBreakerRegistry registry;
CircuitBreaker circuitBreaker = registry.circuitBreaker("payment-gateway");
CircuitBreaker.State state = circuitBreaker.getState();@ApplicationScoped
public class SystemHealthService {
@Inject
CircuitBreakerRegistry circuitBreakerRegistry;
@Inject
MeterRegistry meterRegistry;
public HealthCheckResponse checkCircuitBreakerHealth() {
List<String> openCircuits = new ArrayList<>();
// Check all named circuit breakers
for (String name : circuitBreakerRegistry.getAllCircuitBreakerNames()) {
CircuitBreaker cb = circuitBreakerRegistry.circuitBreaker(name);
if (cb.getState() == CircuitBreaker.State.OPEN) {
openCircuits.add(name);
}
}
if (openCircuits.isEmpty()) {
return HealthCheckResponse.up("circuit-breakers")
.withData("status", "All circuit breakers closed")
.build();
} else {
return HealthCheckResponse.down("circuit-breakers")
.withData("open-circuits", openCircuits)
.build();
}
}
@EventObserver
public void onCircuitBreakerStateChange(CircuitBreakerStateChangeEvent event) {
// Record metrics when circuit breaker state changes
Counter counter = Counter.builder("circuit.breaker.state.changes")
.tag("name", event.getCircuitBreakerName())
.tag("from", event.getFromState().toString())
.tag("to", event.getToState().toString())
.register(meterRegistry);
counter.increment();
}
}Complex patterns combining circuit breakers with other fault tolerance strategies.
@Retry(maxRetries = 3, delay = 1000)
@CircuitBreaker(requestVolumeThreshold = 10, failureRatio = 0.5)
@Timeout(5000)
public ReturnType resilientMethod();@Bulkhead(value = 5, waitingTaskQueue = 10)
@CircuitBreaker(requestVolumeThreshold = 15, failureRatio = 0.4)
public ReturnType isolatedMethod();@ApplicationScoped
public class CriticalService {
// Maximum resilience combination
@Retry(maxRetries = 2, delay = 500)
@CircuitBreaker(
requestVolumeThreshold = 12,
failureRatio = 0.3,
delay = 45000
)
@Timeout(8000)
@Fallback(fallbackMethod = "criticalFallback")
@Bulkhead(value = 3)
public CriticalData performCriticalOperation(String operationId) throws Exception {
return criticalSystemClient.execute(operationId);
}
public CriticalData criticalFallback(String operationId) {
// Emergency fallback - might return cached data or trigger manual process
return emergencyDataSource.getCriticalData(operationId);
}
}// Circuit breaker states
enum CircuitBreakerState {
CLOSED, // Normal operation
OPEN, // Calls blocked
HALF_OPEN // Testing recovery
}
// Circuit breaker registry for programmatic access
interface CircuitBreakerRegistry {
CircuitBreaker circuitBreaker(String name);
Set<String> getAllCircuitBreakerNames();
}
// Circuit breaker instance
interface CircuitBreaker {
State getState();
Metrics getMetrics();
String getName();
enum State {
CLOSED, OPEN, HALF_OPEN, DISABLED, FORCED_OPEN
}
}// Circuit breaker metrics
interface CircuitBreakerMetrics {
int getNumberOfSuccessfulCalls();
int getNumberOfFailedCalls();
int getNumberOfBufferedCalls();
int getNumberOfSlowCalls();
float getFailureRate();
float getSlowCallRate();
Duration getSlowCallRateThreshold();
}// Circuit breaker events for monitoring
interface CircuitBreakerEvent {
String getCircuitBreakerName();
ZonedDateTime getCreationTime();
enum Type {
SUCCESS, ERROR, IGNORED_ERROR, STATE_TRANSITION,
RESET, DISABLED, FORCED_OPEN_STATE
}
}
// State change event
interface CircuitBreakerStateChangeEvent extends CircuitBreakerEvent {
CircuitBreaker.State getFromState();
CircuitBreaker.State getToState();
}Install with Tessl CLI
npx tessl i tessl/maven-io-quarkus--quarkus-smallrye-fault-tolerance