Three States
Circuit Breaker Three States
State Diagram
Closed → Open → Half-Open → Closed
↑ ↓
└────────────────────┘
Closed:
- Normal operation
- Requests pass through
- Count failures
Open:
- Failure threshold exceeded
- Requests fail immediately
- No calls to service
Half-Open:
- Cooldown period elapsed
- Allow one test request
- Check if service recovered
State Transitions
1. Closed → Open:
Trigger: Failure count >= threshold
Action: Start cooldown timer
2. Open → Half-Open:
Trigger: Cooldown period elapsed
Action: Allow one test request
3. Half-Open → Closed:
Trigger: Test request succeeds
Action: Reset failure count
4. Half-Open → Open:
Trigger: Test request fails
Action: Reset cooldown timer
Configuration
class CircuitBreaker:
def __init__(self, failure_threshold=5, recovery_timeout=30):
self.failure_threshold = failure_threshold
self.recovery_timeout = recovery_timeout
self.failure_count = 0
self.last_failure_time = None
self.state = 'closed'
State Impact
| State | Request Behavior | Failure Detection |
|---|---|---|
| Closed | Pass through | Count failures |
| Open | Fail fast | No detection |
| Half-Open | Allow one | Test recovery |
Implementation
Circuit Breaker Implementation
Complete Implementation
import time
import threading
class CircuitBreaker:
def __init__(self, failure_threshold=5, recovery_timeout=30, half_open_max=1):
self.failure_threshold = failure_threshold
self.recovery_timeout = recovery_timeout
self.half_open_max = half_open_max
self.failure_count = 0
self.success_count = 0
self.last_failure_time = None
self.state = 'closed'
self.lock = threading.Lock()
@property
def is_open(self):
with self.lock:
if self.state == 'open':
if time.time() - self.last_failure_time > self.recovery_timeout:
self.state = 'half-open'
self.success_count = 0
return False
return True
return False
def record_success(self):
with self.lock:
self.failure_count = 0
if self.state == 'half-open':
self.success_count += 1
if self.success_count >= self.half_open_max:
self.state = 'closed'
def record_failure(self):
with self.lock:
self.failure_count += 1
self.last_failure_time = time.time()
if self.state == 'half-open':
self.state = 'open'
elif self.failure_count >= self.failure_threshold:
self.state = 'open'
def call(self, func, fallback=None):
if self.is_open:
if fallback:
return fallback()
raise CircuitOpenError('Circuit is open')
try:
result = func()
self.record_success()
return result
except Exception as e:
self.record_failure()
if fallback:
return fallback()
raise
# Usage
circuit = CircuitBreaker(failure_threshold=5, recovery_timeout=30)
try:
result = circuit.call(lambda: call_external_service())
except CircuitOpenError:
result = fallback_response()
With Fallback
class ResilientService:
def __init__(self):
self.circuit = CircuitBreaker()
def get_user(self, user_id):
try:
return self.circuit.call(
lambda: self.primary_db.get_user(user_id)
)
except CircuitOpenError:
# Fallback to cache or secondary
return self.cache.get_user(user_id)
Monitoring
def monitor_circuit_breaker(circuit, service_name):
metrics = {
'state': circuit.state,
'failure_count': circuit.failure_count,
'is_open': circuit.is_open
}
metrics.gauge(f'{service_name}.circuit.state',
['closed', 'open', 'half-open'].index(circuit.state))
metrics.counter(f'{service_name}.circuit.failures', circuit.failure_count)
Best Practices
- Set appropriate thresholds based on service
- Use fallbacks when circuit is open
- Monitor circuit state
- Log state transitions
- Test failure scenarios
Integration with Retries
Circuit Breaker + Retry Integration
Combined Pattern
Request → Circuit Breaker Check
↓
[Open] → Fail fast (no retry)
[Closed] → Retry Logic
↓
Attempt → Success → Return
Attempt → Fail → Backoff → Retry
All Fail → Record Failure → Circuit Open
Implementation
class ResilientCaller:
def __init__(self, circuit_breaker, retry_policy):
self.circuit = circuit_breaker
self.retry = retry_policy
def call(self, func, *args, **kwargs):
# Check circuit first
if self.circuit.is_open:
raise CircuitOpenError('Circuit is open')
# Retry with backoff
last_exception = None
for attempt in range(self.retry.max_retries):
try:
result = func(*args, **kwargs)
self.circuit.record_success()
return result
except Exception as e:
last_exception = e
self.circuit.record_failure()
if attempt < self.retry.max_retries - 1:
delay = self.retry.get_delay(attempt)
time.sleep(delay)
raise last_exception
Flow with Integration
1. Request arrives
2. Circuit open? → Yes → Fail fast
3. Circuit closed? → Continue
4. Attempt call
5. Success → Record success, return
6. Failure → Record failure
7. More retries? → Wait (backoff) → Retry
8. No more retries → Raise exception
9. Circuit opens if threshold exceeded
Configuration Example
# Configuration
circuit_config = {
'failure_threshold': 5,
'recovery_timeout': 30
}
retry_config = {
'max_retries': 3,
'base_delay': 1,
'max_delay': 30,
'jitter': True
}
# Create components
circuit = CircuitBreaker(**circuit_config)
retry = RetryPolicy(**retry_config)
caller = ResilientCaller(circuit, retry)
# Use
result = caller.call(service_api, param1, param2)
Monitoring
def monitor_resilience(caller, service_name):
metrics = {
'circuit_state': caller.circuit.state,
'failure_count': caller.circuit.failure_count,
'retry_rate': get_retry_rate(service_name)
}
# Alert on open circuit
if caller.circuit.is_open:
alert(f'{service_name}: Circuit is open')
Best Practices
- Use circuit breaker first (fast fail)
- Retry only when circuit closed
- Use fallbacks when circuit open
- Monitor both metrics
- Test failure scenarios
Practice Problems
Design a scalable Circuit Breaker system. Cover high-level architecture, data model, and API design.
Solution
// Complete system design:
// - Functional + Non-functional requirements
// - Capacity estimation
// - Data model (SQL/NoSQL choice)
// - API endpoints
// - Component architecture
// - Scaling strategy
// - Monitoring & reliabilityHow would you scale Circuit Breaker to handle 10x the current load? Identify bottlenecks and solutions.
Solution
// Scaling approach:
// 1. Load balancing
// 2. Database sharding/replication
// 3. Cache layer (Redis)
// 4. CDN for static assets
// 5. Async processing (queues)
// 6. Microservices decompositionAnalyze potential failure modes for Circuit Breaker and design mitigation strategies.
Solution
// Failure mitigation:
// 1. Redundancy (multi-AZ)
// 2. Circuit breakers
// 3. Retry with backoff
// 4. Dead letter queues
// 5. Health checks
// 6. Graceful degradationQuiz
1. What are the three states of a circuit breaker?
2. When does circuit breaker transition from Closed to Open?
3. What is the purpose of Half-Open state?
4. What happens when circuit is open?
5. Why combine circuit breaker with retry?
Flashcards
Question
Three circuit breaker states?
Click to reveal answer
Answer
Closed (normal), Open (fail fast), Half-Open (test recovery)
Question
Closed → Open transition?
Click to reveal answer
Answer
When failure count reaches threshold - circuit opens to prevent more calls to failing service
Question
What is Half-Open state?
Click to reveal answer
Answer
Allows one test request to check if failed service has recovered before fully closing circuit
Question
Circuit breaker + retry integration?
Click to reveal answer
Answer
Check circuit first (fail fast if open), then retry with backoff if circuit is closed
Question
Why use fallback with circuit breaker?
Click to reveal answer
Answer
Provide alternative response when circuit is open and primary service is unavailable
Revision Notes
Key Takeaways
- 1.Three states: Closed, Open, Half-Open
- 2.Closed → Open on failure threshold
- 3.Half-Open tests recovery with one request
- 4.Combine with retry for resilience
- 5.Always provide fallback when circuit is open
Interview Tips
- •Draw state diagram with transitions
- •Explain each state's purpose
- •Discuss integration with retry logic
- •Mention monitoring and fallbacks
Cheat Sheet
Cheat Sheet: Circuit Breaker
Three States
- Closed: Normal, count failures
- Open: Fail fast, no calls
- Half-Open: Test recovery
Transitions
- Closed → Open: threshold reached
- Open → Half-Open: cooldown elapsed
- Half-Open → Closed: test success
- Half-Open → Open: test failure
Integration
Circuit Check → Retry → Fallback
Configuration
- failure_threshold: 5
- recovery_timeout: 30s
- half_open_max: 1
Best Practices
- Use fallbacks
- Monitor state
- Log transitions