← Home
🏗Crack System Design with DSA AnimatorSystem DesignNEW
🏗 System Design›Reliability & Scalability

🧩Circuit Breakers & Retries (Resilience4j)

Prevent cascading failures with fail-fast circuit breakers and safe retry policies.

📌 Key IdeaUse Retry for transient errors and Circuit Breaker for sustained failures. In Resilience4j, tune thresholds, sliding windows, backoff+jitter, and idempotency boundaries; otherwise retries can amplify outages.
🧩

Problem it solves

  • Dependency failures can cascade and exhaust thread pools if every request keeps waiting/retrying blindly.
  • Transient and sustained failures need different handling strategies.
  • Resilience4j helps you fail fast, retry safely, and recover predictably with explicit policies.
📖

Definition

Resilience4j is a lightweight fault-tolerance library for Java/Spring Boot. It provides CircuitBreaker, Retry, TimeLimiter, Bulkhead, and RateLimiter modules, with annotations or programmatic composition.

✨

Why It Matters

  • Stops dependency outages from exhausting request threads.
  • Improves recovery speed with controlled retries and half-open probes.
  • Provides production metrics/events for resilience tuning.
💻

Code Variations

1️⃣ application.yml baseline configyaml
resilience4j:
  retry:
    instances:
      paymentRetry:
        maxAttempts: 3
        waitDuration: 200ms
        enableExponentialBackoff: true
        exponentialBackoffMultiplier: 2
  circuitbreaker:
    instances:
      paymentCb:
        slidingWindowType: COUNT_BASED
        slidingWindowSize: 20
        minimumNumberOfCalls: 10
        failureRateThreshold: 50
        slowCallRateThreshold: 60
        slowCallDurationThreshold: 2s
        waitDurationInOpenState: 10s
        permittedNumberOfCallsInHalfOpenState: 5
Tune using real traffic metrics; defaults are rarely optimal for all dependencies.
2️⃣ Spring Boot annotation usagejava
@Service
class PaymentGatewayClient {

  @Retry(name = "paymentRetry", fallbackMethod = "fallback")
  @CircuitBreaker(name = "paymentCb", fallbackMethod = "fallback")
  public PaymentResponse charge(PaymentRequest req) {
    return httpClient.charge(req);
  }

  public PaymentResponse fallback(PaymentRequest req, Throwable t) {
    return PaymentResponse.accepted("queued_for_retry");
  }
}
Fallback should be explicit business behavior, not hidden silent success.
3️⃣ Idempotent retry boundaryjava
public PaymentResponse charge(PaymentRequest req) {
  String key = req.idempotencyKey();
  if (processedRepo.existsById(key)) return processedRepo.get(key);

  PaymentResponse r = gateway.charge(req); // retriable only if safe
  processedRepo.save(key, r);
  return r;
}
Retries on non-idempotent writes can cause double charges/orders.
📊

Retry vs Circuit Breaker in practice

AspectRetryCircuit Breaker
Primary goalRecover transient failuresFail fast during sustained failures
When triggeredOn selected exceptions/statusesWhen failure/slow-call thresholds exceed limits
Key knobsAttempts, wait duration, backoff+jitterSliding window, failure rate, wait in OPEN, half-open calls
Biggest riskRetry storm under outageToo aggressive opening causing false fail-fast
Must-have pairingIdempotency + timeoutFallback + observability + timeout
🔀

Common Confusions Cleared Up

Retries are for blips; breaker is for outages

If dependency is hard-down, retries just add pressure. Breaker should open quickly to protect your service and downstream.

Half-open is a probe mode, not full recovery

Allow limited calls in HALF_OPEN to test dependency health before closing circuit.

Slow-call threshold is as important as failure threshold

High latency can cause thread-pool starvation even with low error rate; track both slow calls and failures.

🧪

Variations / Implementations

Recommended call chain

Timeout first, then retry (for retriable failures), then circuit breaker for sustained faults. Keep retries bounded and only for idempotent operations.

Annotation-driven Spring style

Use @CircuitBreaker, @Retry, @TimeLimiter with named configs and fallback methods for readable policy management.

Programmatic decorators

Use Resilience4j decorators when you need explicit policy composition and runtime control in non-Spring layers.

⚠️

Common Mistakes / Anti-Patterns

  • Retrying all exceptions blindly (including validation/auth errors).
  • No timeout configured, causing long hangs.
  • Fallback returning stale/incorrect data without signaling degraded mode.
  • Same breaker config for all dependencies despite different latency/error profiles.
  • No monitoring of OPEN/HALF_OPEN transitions.
🎤

Interview Q&A

🧾

Quick Cheat Sheet

Retry ruleBounded attempts + backoff+jitter + idempotency.
Breaker ruleOpen on sustained failure/latency, half-open probe recovery.
Timeout ruleAlways set timeouts before retry logic.
Ops ruleTune per dependency, not one global config.
🔗

Related Topics