Circuit breakers don’t just trip; they actively participate in load balancing by selectively shedding load to prevent catastrophic failures.

Let’s watch a circuit breaker in action. Imagine a simple web service, UserService, that depends on an external EmailService. We’ll use a Java application with Resilience4j for our circuit breaker.

Here’s the UserService code:

@Service
public class UserService {

    private final EmailService emailService;
    private final CircuitBreaker circuitBreaker;

    public UserService(EmailService emailService) {
        this.emailService = emailService;
        this.circuitBreaker = CircuitBreaker.ofDefaults("emailServiceCircuitBreaker");
    }

    public String registerUser(String username) {
        // Decorate the call to emailService.sendWelcomeEmail with the circuit breaker
        Supplier<String> emailCall = () -> emailService.sendWelcomeEmail(username);
        String result = circuitBreaker.executeSupplier(emailCall);
        return "User " + username + " registered. Email status: " + result;
    }
}

And the EmailService (which will simulate failures):

@Service
public class EmailService {

    private int requestCount = 0;

    public String sendWelcomeEmail(String username) {
        requestCount++;
        if (requestCount % 3 == 0) { // Simulate failure every 3rd call
            throw new RuntimeException("Email service is overloaded!");
        }
        return "Welcome email sent to " + username;
    }
}

We configure Resilience4j’s circuit breaker in application.yml:

resilience4j.circuitbreaker:
  instances:
    emailServiceCircuitBreaker:
      registerHealthIndicator: true
      slidingWindowType: COUNT_BASED
      slidingWindowSize: 10 # Consider the last 10 calls
      minimumNumberOfCalls: 5  # At least 5 calls before considering a trip
      permittedNumberOfCallsInHalfOpenState: 3 # Allow 3 calls in half-open
      automaticTransitionFromOpenToHalfOpenEnabled: true
      waitDurationInOpenState: 5s # Wait 5 seconds before moving to half-open
      recordExceptions: # Exceptions that count towards tripping
        - java.lang.RuntimeException

Now, let’s simulate load testing. We’ll hit the registerUser endpoint repeatedly.

  1. First few calls: UserService calls EmailService. EmailService succeeds. Circuit breaker records successes.
  2. Third call: EmailService throws RuntimeException. Circuit breaker records a failure.
  3. Fourth, Fifth calls: EmailService succeeds again. Circuit breaker still sees a low failure rate.
  4. Sixth call: EmailService throws RuntimeException. The failure rate now crosses the threshold (e.g., if 3 out of 6 calls failed, and our threshold is 50%, it trips). The circuit breaker transitions to OPEN.
  5. Subsequent calls (while OPEN): UserService no longer calls EmailService. The circuitBreaker.executeSupplier(emailCall) immediately returns a fallback (or throws a CallNotPermittedException). The UserService returns "User X registered. Email status: Circuit breaker is open." This protects EmailService from further load.
  6. After waitDurationInOpenState (5s): The circuit breaker automatically transitions to HALF-OPEN.
  7. First call in HALF-OPEN: UserService calls EmailService. If it succeeds, the circuit breaker transitions back to CLOSED. If it fails, it goes back to OPEN for another 5 seconds.
  8. Subsequent calls in HALF-OPEN: If the circuit breaker is HALF-OPEN, it allows a limited number of calls (permittedNumberOfCallsInHalfOpenState). If these succeed, it closes. If any fail, it opens again.

This dance of CLOSED, OPEN, and HALF-OPEN states, driven by call statistics and configured thresholds, is the core of circuit breaker behavior.

The most surprising thing about circuit breakers is that they don’t just react to failures; they anticipate them based on past behavior and actively prevent them by short-circuiting. The HALF-OPEN state is crucial for recovery, acting as a canary test to see if the downstream service has healed before fully re-engaging it.

The next step is understanding how to integrate different fallback mechanisms when the circuit breaker is open, beyond just returning an error.

Want structured learning?

Take the full Circuit-breaker course →