Обработка ошибок: таймауты, повторы, backoff
Сеть ненадёжна, а провайдер иногда перегружен. Устойчивый код это предусматривает.
Экспоненциальный backoff — стратегия повторов, где задержка между попытками растёт по экспоненте (1с, 2с, 4с...), часто с добавлением случайного «джиттера».
Какие ошибки бывают и что с ними делать
| Код | Причина | Повторять? |
| 400 | ошибка в запросе (формат, параметры) | нет — чините запрос |
| 401 | неверный ключ | нет — чините ключ |
| 429 | превышен rate limit | да — после паузы |
| 500 / 529 | сбой/перегрузка сервера | да — с backoff |
| таймаут соединения | сеть/долгий ответ | да — с backoff |
Главное: повторять стоит только «временные» ошибки (429, 5xx, таймауты). Ошибки запроса (4xx, кроме 429) повторять бессмысленно — они не пройдут и со второго раза.
SDK уже это умеют
Официальные клиенты Anthropic и OpenAI автоматически повторяют 429 и 5xx с backoff. Часто достаточно настроить число повторов и таймаут — свой цикл не нужен.
import anthropic, httpx
client = anthropic.Anthropic(
max_retries=5, # сколько раз повторить
timeout=httpx.Timeout(30.0),
)
try:
resp = client.messages.create(
model="claude-opus-4-8",
max_tokens=512,
messages=[{"role": "user", "content": "..."}],
)
except anthropic.RateLimitError as e:
# сюда попадём, если повторы исчерпаны
print("Лимит исчерпан:", e)
except anthropic.APIStatusError as e:
print("Ошибка API:", e.status_code)
Расчёт задержек backoff (запускаемо)
Посмотрим, как растут паузы между попытками. Джиттер делаем детерминированным (фиксируем seed) ради воспроизводимого вывода — чистый Python:
import random
random.seed(42) # детерминированный вывод для урока
def backoff_delays(max_retries=5, base=1.0, cap=60.0):
delays = []
for attempt in range(max_retries):
raw = base * (2 ** attempt) # 1, 2, 4, 8, 16...
jitter = random.uniform(0, 1) # случайная добавка
delays.append(round(min(raw + jitter, cap), 2))
return delays
for i, d in enumerate(backoff_delays()):
print(f"Попытка {i+1}: ждём {d} c")
Вывод:
Попытка 1: ждём 1.64 c Попытка 2: ждём 2.03 c Попытка 3: ждём 4.28 c Попытка 4: ждём 8.22 c Попытка 5: ждём 16.74 c
Джиттер (случайная добавка) важен: без него тысячи клиентов, упёршихся в лимит одновременно, повторят запрос в одну и ту же секунду и снова создадут пик. Разброс «размазывает» нагрузку.
Итог
- Повторяйте только временные ошибки: 429, 5xx, таймауты; запросные (4xx) — чините.
- Backoff: задержка растёт экспоненциально, плюс джиттер против синхронных пиков.
- SDK делают повторы сами — настройте
max_retriesиtimeout.