Circuit Breaker Pattern
Implement a circuit breaker with states (closed, open, half-open), failure counting, and auto-recovery.
import java.time.Instant;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
public class CircuitBreaker {
enum State { CLOSED, OPEN, HALF_OPEN }
private final int failureThreshold;
private final long resetTimeoutMs;
private final AtomicInteger failureCount = new AtomicInteger(0);
private final AtomicReference<State> state = new AtomicReference<>(State.CLOSED);
private volatile Instant lastFailureTime = Instant.MIN;
public CircuitBreaker(int failureThreshold, long resetTimeoutMs) {
this.failureThreshold = failureThreshold;
this.resetTimeoutMs = resetTimeoutMs;
}
public <T> T execute(Supplier<T> action, Supplier<T> fallback) {
if (!allowRequest()) {
System.out.println("Circuit OPEN — using fallback");
return fallback.get();
}
try {
T result = action.get();
onSuccess();
return result;
} catch (Exception e) {
onFailure();
return fallback.get();
}
}
private boolean allowRequest() {
return switch (state.get()) {
case CLOSED -> true;
case OPEN -> {
if (Instant.now().toEpochMilli() - lastFailureTime.toEpochMilli() > resetTimeoutMs) {
state.set(State.HALF_OPEN);
System.out.println("Circuit HALF_OPEN — testing");
yield true;
}
yield false;
}
case HALF_OPEN -> true;
};
}
private void onSuccess() {
failureCount.set(0);
if (state.get() == State.HALF_OPEN) {
state.set(State.CLOSED);
System.out.println("Circuit CLOSED — recovered");
}
}
private void onFailure() {
lastFailureTime = Instant.now();
int failures = failureCount.incrementAndGet();
if (failures >= failureThreshold) {
state.set(State.OPEN);
System.out.println("Circuit OPEN — threshold reached (" + failures + ")");
}
}
public State getState() { return state.get(); }
public static void main(String[] args) throws Exception {
CircuitBreaker breaker = new CircuitBreaker(3, 2000);
var rng = new java.util.Random();
for (int i = 0; i < 10; i++) {
String result = breaker.execute(
() -> {
if (rng.nextBoolean()) throw new RuntimeException("Fail");
return "OK";
},
() -> "FALLBACK"
);
System.out.printf("Request %d: %s (state: %s)%n", i, result, breaker.getState());
Thread.sleep(500);
}
}
}Use Cases
- Protecting services from cascading failures
- Graceful degradation with fallback responses
- Self-healing connection management
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
Builder Pattern — Fluent Object Construction
Implement the Builder pattern for complex objects with validation, immutability, and method chaining.
Best for: Constructing complex objects with many optional parameters
Singleton Pattern — Thread-Safe Approaches
Implement thread-safe singletons in Java: enum, holder class, double-checked locking, and eager init.
Best for: Application-wide configuration managers
Strategy Pattern with Lambdas
Implement the Strategy pattern using interfaces and Java lambdas for flexible algorithm selection.
Best for: Swappable pricing or discount algorithms
Factory Method Pattern with Registry
Implement the Factory pattern using a registry map for extensible object creation without switch statements.
Best for: Extensible object creation in plugin architectures