Короткий ответ
Timeout ограничивает, сколько вы готовы ждать один вызов; retry повторяет вызов при временном сбое (обычно с экспоненциальной задержкой); circuit breaker временно прекращает попытки вызова сервиса, который стабильно отказывает, чтобы не тратить ресурсы и не усугублять его перегрузку.
Как это работает подробнее
эти три механизма решают разные проблемы и обычно применяются вместе: timeout защищает от бесконечного ожидания одного вызова, retry сглаживает кратковременные сетевые сбои, circuit breaker защищает систему от продолжительной недоступности зависимости, переводя вызовы в "открытое" состояние (быстрый отказ без реального запроса) на время восстановления.
Пример кода
example.py
import time
import random
import requests
def call_with_retry(url, max_attempts=3, base_delay=0.5):
for attempt in range(1, max_attempts + 1):
try:
resp = requests.get(url, timeout=3)
resp.raise_for_status()
return resp.json()
except requests.exceptions.RequestException as exc:
if attempt == max_attempts:
raise
delay = base_delay * (2 ** (attempt - 1)) + random.uniform(0, 0.1)
time.sleep(delay) # экспоненциальный backoff с джиттеромЧто использовать на практике
- Рекомендация. retry стоит применять только к идемпотентным операциям или операциям с защитой идемпотентности (см. idempotency key), иначе повтор может продублировать побочный эффект; задержку между попытками стоит увеличивать экспоненциально с джиттером, чтобы не создавать синхронизированный всплеск нагрузки ("thundering herd") на восстанавливающийся сервис. Количество попыток и пороги circuit breaker должны быть основаны на реальных SLA зависимости и критичности операции для пользователя — универсальных "правильных" чисел нет.
Подводные камни
- Риски. делать retry для неидемпотентных операций без ключа идемпотентности, создавая дубликаты; ставить retry без ограничения общего времени (суммарный backoff может растянуться на минуты, пока пользователь ждёт ответа); не логировать переходы circuit breaker между состояниями, из-за чего невозможно понять в production, почему сервис вдруг стал быстро отказывать без реальных попыток вызова.