How to Mock a Circuit Breaker Reset Timeout in Python
This code implements a simple circuit breaker with a reset timeout test, simulating a flaky service to show half-open state transitions.
Python code
57 linesimport time
import random
class CircuitBreaker:
def __init__(self, failure_threshold=3, reset_timeout=5):
self.failure_threshold = failure_threshold
self.reset_timeout = reset_timeout
self.failure_count = 0
self.last_failure_time = None
self.state = "CLOSED" # CLOSED (normal), OPEN (tripped), HALF_OPEN (testing)
def call(self, func):
if self.state == "OPEN":
if time.time() - self.last_failure_time >= self.reset_timeout:
self.state = "HALF_OPEN"
print("Circuit half-open: testing one request")
else:
print("Circuit OPEN: request rejected immediately")
raise Exception("Circuit breaker is open")
try:
result = func()
if self.state == "HALF_OPEN":
self.state = "CLOSED"
self.failure_count = 0
print("Circuit closed after successful half-open test")
else:
self.failure_count = 0
return result
except Exception as e:
self.failure_count += 1
self.last_failure_time = time.time()
if self.failure_count >= self.failure_threshold:
self.state = "OPEN"
print(f"Circuit OPEN after {self.failure_count} failures")
raise e
# Simulated flaky service
def flaky_service():
if random.random() < 0.6:
raise ConnectionError("Service unavailable")
return "Success"
if __name__ == "__main__":
breaker = CircuitBreaker()
for attempt in range(10):
try:
result = breaker.call(flaky_service)
print(f"Attempt {attempt + 1}: {result}")
except Exception as e:
print(f"Attempt {attempt + 1}: FAILED ({e})")
time.sleep(1.5)
print(f"Final state: {breaker.state}")
Output
Circuit OPEN after 3 failures
Attempt 1: FAILED (Service unavailable)
Attempt 2: FAILED (Service unavailable)
Attempt 3: FAILED (Service unavailable)
Circuit OPEN: request rejected immediately
Attempt 4: FAILED (Circuit breaker is open)
Attempt 5: FAILED (Circuit breaker is open)
Circuit half-open: testing one request
Attempt 6: FAILED (Service unavailable)
Circuit OPEN after 4 failures
Attempt 7: FAILED (Service unavailable)
Circuit OPEN: request rejected immediately
Attempt 8: FAILED (Circuit breaker is open)
Circuit half-open: testing one request
Attempt 9: Success
Circuit closed after successful half-open test
Attempt 10: Success
Final state: CLOSED
How it works
The circuit breaker tracks consecutive failures and trips to OPEN when the threshold is reached. After reset_timeout seconds, it enters HALF_OPEN and lets one test request through. If that request succeeds, the circuit resets to CLOSED; if it fails, it returns to OPEN. The mock uses random failures to simulate a flaky service and time.sleep to control the reset timeout.
Common mistakes
- Forgetting to update last_failure_time when a single request fails, causing open state to never reset
- Resetting failure_count on success even when circuit is not half-open, masking repeated failures
- Not handling exceptions in the half-open state correctly, leading to premature closing
Variations
- Use the 'pybreaker' library for a production-grade circuit breaker with more features
- Implement the reset timeout check using a background thread or async timer instead of blocking
Real-world use cases
- Wrapping calls to an unreliable third-party API to prevent cascading failures in a microservice
- Protecting a database connection during peak load when the database may become temporarily unavailable
- Avoiding repeated retries to a downed backend service in a job scheduler, reducing load and wait time
Sponsored
More from Reliability & rate limiting
- At Least Once with Idempotent Consumer in Python medium
- Build a Rate Limiter Decorator in Python easy
- Build a queue-based admission control system in Python easy
- Chaos Inject Random Failures in Python easy
- Circuit breaker failure threshold count in Python medium
- Exactly Once Processing Dedupe Mock in Python easy
Keep learning
Related tutorials and quizzes for this topic.