**Approach (brief)**Implement a stateful CircuitBreaker with states CLOSED, OPEN, HALF_OPEN. Track recent failures in a rolling window, open when failures ≥ threshold N, reject requests while OPEN, after cooldown move to HALF_OPEN and allow a single probe; success resets to CLOSED, failure returns to OPEN.**Pseudocode / Java**java
public class CircuitBreaker {
enum State { CLOSED, OPEN, HALF_OPEN }
private State state = State.CLOSED;
private final int failureThreshold;
private final Duration window;
private final Duration cooldown;
private final Deque<Long> failureTimestamps = new ArrayDeque<>();
private long openUntil = 0;
private final AtomicBoolean probeInFlight = new AtomicBoolean(false);
public CircuitBreaker(int failureThreshold, Duration window, Duration cooldown) {
this.failureThreshold = failureThreshold;
this.window = window;
this.cooldown = cooldown;
}
public <T> T call(Supplier<T> remoteCall, Supplier<T> fallback) {
long now = System.currentTimeMillis();
pruneOldFailures(now);
if (state == State.OPEN) {
if (now >= openUntil) {
state = State.HALF_OPEN;
} else {
emit("rejected");
return fallback.get();
}
}
if (state == State.HALF_OPEN) {
if (!probeInFlight.compareAndSet(false, true)) {
emit("rejected");
return fallback.get();
}
}
try {
T result = remoteCall.get();
onSuccess();
return result;
} catch (Exception e) {
onFailure(now);
return fallback.get();
} finally {
probeInFlight.set(false);
}
}
private void onSuccess() {
failureTimestamps.clear();
state = State.CLOSED;
emit("success");
}
private void onFailure(long now) {
failureTimestamps.addLast(now);
pruneOldFailures(now);
emit("failure");
if (failureTimestamps.size() >= failureThreshold) {
state = State.OPEN;
openUntil = now + cooldown.toMillis();
emit("opened");
} else if (state == State.HALF_OPEN) {
state = State.OPEN;
openUntil = now + cooldown.toMillis();
emit("opened");
}
}
private void pruneOldFailures(long now) {
long cutoff = now - window.toMillis();
while (!failureTimestamps.isEmpty() && failureTimestamps.peekFirst() < cutoff) {
failureTimestamps.removeFirst();
}
}
private void emit(String metric) { /* hook to metrics system */ }
}
**Metrics to emit**- counter.calls_total, counter.calls_failed, counter.calls_success- gauge.state {CLOSED/OPEN/HALF_OPEN}- counter.rejections (requests rejected while OPEN or concurrent HALF_OPEN)- histogram/latency for remote calls- counter.open_events, counter.probe_success, counter.probe_failure**Tuning guidance**- failureThreshold N: start small (3–5) for high-sensitivity services; increase for noisy transient errors.- rolling window: match expected error clustering (e.g., 30s–2m).- cooldown: long enough for downstream recovery (seconds–minutes); use exponential backoff on repeated opens.- monitor metrics (rejection rate, probe success) and adjust: if many false opens, raise N or shorten sensitivity; if system overload persists, shorten cooldown or reduce allowed probes.- add safeties: circuit-wide rate limits, jitter on probe timing, persistent state across instances if needed.