Короткий ответ
Устойчивость строят комбинацией таймаутов, ограниченных retry с backoff и джиттером, circuit breaker и осмысленного fallback (включая кеш последнего успешного ответа) — конкретный набор и агрессивность этих механизмов зависят от критичности операции.
Как это работает подробнее
Таймаут ограничивает время ожидания одной попытки; retry даёт шанс на успех при кратковременных сбоях; circuit breaker прекращает бесполезные попытки при затяжной деградации; fallback позволяет не отказывать пользователю полностью.
Более агрессивная защита увеличивает видимую надёжность, но может маскировать реальные проблемы зависимости надолго и увеличивает сложность тестирования; более консервативная защита проще и честнее относительно актуальности данных, но может чаще показывать ошибки при кратковременных сбоях. Критерий выбора — критичность актуальности данных для операции и готовность бизнеса принимать риск устаревшего fallback против риска более частых отказов.
Пример кода
def get_fx_rate(currency):
if fx_breaker.is_open():
return cache.get(f"fx:{currency}") or default_rate(currency)
try:
rate = fx_client.get_rate(currency, timeout=2)
cache.set(f"fx:{currency}", rate, ex=120)
return rate
except (TimeoutError, HTTPError):
fx_breaker.record_failure()
return cache.get(f"fx:{currency}") or default_rate(currency)Что использовать на практике
- Практика. Для некритичных дополняющих данных кеш последнего успешного ответа как fallback почти всегда оправдан; для критичных операций (списание денег, проверка доступа) fallback на устаревшие данные может быть опасен, и честная ошибка безопаснее.
Подводные камни
- Риск. Применять один и тот же fallback для всех видов интеграций без оценки риска использования устаревших данных; наращивать число retry и уменьшать таймаут бесконтрольно без учёта суммарного времени ожидания.