Circuit Breaker States
A circuit breaker typically moves among closed, open, and half-open states to detect repeated failures and isolate an unhealthy dependency. Understanding each state and its transitions is essential when designing resilient Java backend services.
In the closed state, requests are allowed to reach the protected dependency. The breaker records failures according to its configured policy, such as exceptions or timeouts. When failures cross a configured threshold, the breaker transitions to open.
In the open state, calls are rejected immediately instead of being sent to the failing dependency. This prevents repeated attempts from consuming threads, connections, and latency budgets. After a configured wait interval, the breaker permits a limited test by moving to half-open.
The half-open state tests whether the dependency has recovered. A successful test, or successful permitted calls according to the implementation, can return the breaker to closed. If the test fails, the breaker normally returns to open and waits before trying again.
State transitions are implementation-specific in their exact thresholds and sampling rules. A production design should therefore distinguish the general three-state model from configuration details such as failure-rate thresholds, minimum call counts, wait durations, and permitted test calls.
Key points
- Closed allows calls and tracks failures.
- Open rejects calls quickly during the recovery wait period.
- Half-open permits limited test traffic to assess recovery.
- A successful recovery test can move the breaker back to closed.
- A failed half-open test typically sends the breaker back to open.
Interview questions
What are the three states of a circuit breaker?
The common states are closed, open, and half-open. Closed means calls are permitted and failures are monitored. Open means calls are rejected without contacting the dependency. Half-open allows limited test calls to determine whether the dependency has recovered.
Why is the open state useful if requests already have timeouts?
A timeout limits the duration of one request, but it does not prevent every new request from attempting the unhealthy dependency. During an outage, many timed-out calls can still consume threads, connections, and latency budget. An open circuit rejects calls quickly and reduces pressure on the failing service. The two mechanisms therefore address different parts of the failure behavior.
What should happen when a circuit breaker enters half-open?
The breaker should allow a controlled amount of traffic to test the dependency rather than immediately restoring unrestricted traffic. If the test succeeds according to the configured recovery policy, the breaker can return to closed. If the test fails, it should normally return to open. The exact number of permitted calls and success criteria depend on the implementation.
How would you choose a circuit breaker's failure threshold?
I would choose it from the dependency's normal error behavior, traffic volume, latency objectives, and the cost of sending requests during an outage. A percentage alone can be misleading at low traffic, so many implementations also use a minimum sample size or similar guard. I would validate the settings with production-like failure tests and monitor both false openings and delayed protection. The threshold should be treated as an operational tuning parameter rather than a universal constant.
What problems can occur if retries and circuit breakers are combined carelessly?
Retries can multiply the number of calls made to an already unhealthy dependency, increasing load during an incident. Depending on where the breaker is placed, retry attempts may also interact with breaker failure accounting in unexpected ways. I would use bounded retries, appropriate backoff, and a clear policy for which failures are retryable. The overall design should ensure that retries do not undermine the circuit breaker's purpose of reducing pressure.