Все же знают максимально простую человеческую мудрость: если что-то не работает, сначала попробуй перезагрузить. Это работает не только с компьютерами, но и с нашими запросами.
Внешние API и распределенные системы — это агрессивная среда. Если вы работаете с LLM вроде ChatGPT или Claude, вы не можете гарантировать 100% аптайм или стабильный ответ. Единственное, что вы можете гарантировать — это факт вашей попытки достучаться до эндпоинта.
Ловушка вложенных try-catch
Первое инстинктивное решение — обернуть запрос в
try-catch. Если упало — вызываем запрос еще раз внутри блока catch. Но это путь к бесконечной вложенности и «гонке вооружений» с неопределенностью. Вы не знаете, сколько раз упадет сервер: два, три или десять. Дублирование логики обработки ошибок делает код хрупким и невыносимым в дебаге.Инженерный подход требует выноса логики повторов в отдельный управляемый механизм. Базовый вариант — отложенный повтор. Вместо того чтобы стучать в закрытую дверь каждые 100 миллисекунд, мы должны дать удаленной системе «продышаться» пару секунд. За это время на сервере может инвалидироваться кэш или завершиться процесс очистки памяти, который мешал обработке вашего запроса.
Экспоненциальное ожидание и фактор хаоса
Но простой линейный ретрай (повтор каждые 2 секунды) — это риск само-DDoS’а. Представьте, что у 1000 пользователей одновременно отвалился бэкенд. Если у всех зашит жесткий интервал, то через 2 секунды сервер получит волну из 1000 новых запросов, потом еще одну через 2 секунды. Вместо восстановления вы добьете систему ритмичными ударами.
Решение — Exponential Backoff. Мы увеличиваем паузу после каждой неудачи: 1, 2, 4, 8, 16 секунд. Это разгружает сеть, но оставляет проблему «волн», когда тысячи клиентов синхронно ждут и синхронно бьют в одну и ту же дверь.
Чтобы размазать нагрузку, в формулу добавляется Jitter (джиттер) — контролируемый хаос. Мы берем наше экспоненциальное время и умножаем на случайный коэффициент. В итоге один клиент повторит запрос через 4.1 секунды, второй — через 3.8, а третий — через 4.5. Нагрузка на сервер становится размазанной и плавной, что дает системе реальный шанс вернуться в строй.
Идемпотентность: Главный предохранитель
Ретраи бесполезны и даже опасны без понимания идемпотентности. Это свойство системы выдавать один и тот же результат при повторении идентичного запроса без побочных эффектов.
Если вы ретраите запрос на получение данных (GET) — это безопасно. Но если вы ретраите списание средств или создание заказа без ключа идемпотентности, вы рискуете списать деньги дважды или создать дублирующие записи в базе. Бэкенд должен уметь определять: «Так, этот запрос с ID #555 я уже видел и успешно обработал, просто верну старый результат», вместо того чтобы запускать логику транзакции заново.
Инженер не просто повторяет действие, пока оно не сработает. Он проектирует систему так, чтобы повторы не разрушали целостность данных.
🔥 — если пост был понятен. А если остались вопросы или что-то звучит слишком абстрактно — пиши в комменты, обязательно разберем!
10МДК | ВЕБМастер
