This code shows how adding a circuit breaker and retry logic protects the system from repeated failures and temporary glitches, which is essential in production environments.
### Before: No advanced failure handling
def fetch_data():
response = external_service_call()
return response.data
### After: Using retry and circuit breaker pattern
import time
class CircuitBreaker:
def __init__(self, max_failures=3, reset_timeout=10):
self.failures = 0
self.max_failures = max_failures
self.reset_timeout = reset_timeout
self.last_failure_time = None
self.open = False
def call(self, func, *args, **kwargs):
if self.open:
if time.time() - self.last_failure_time > self.reset_timeout:
self.open = False
self.failures = 0
else:
raise Exception("Circuit breaker is open")
try:
result = func(*args, **kwargs)
self.failures = 0
return result
except Exception:
self.failures += 1
self.last_failure_time = time.time()
if self.failures >= self.max_failures:
self.open = True
raise
def retry(func, retries=3, delay=1):
for i in range(retries):
try:
return func()
except Exception:
if i == retries - 1:
raise
time.sleep(delay)
circuit_breaker = CircuitBreaker()
def fetch_data():
return circuit_breaker.call(retry, external_service_call)
# Explanation:
# The before code calls an external service directly without handling failures.
# The after code wraps the call with a circuit breaker to stop calls after repeated failures
# and retries the call a few times before failing, improving system resilience.