Rate limit и retry: базовая схема для надёжных интеграций
Следующий шаг
Открой бота или продолжай маршрут внутри раздела.
Статья -> план в ИИ
Отправь ссылку на эту статью в любой ИИ и получи план внедрения под свой проект.
Прочитай эту статью: https://vibecode.morecil.ru/ru/integratsii-i-api/rate-limit-i-retry-bazovaya-skhema/
Работай в контексте моего текущего проекта.
Сделай план внедрения под мой стек:
1) что изменить
2) в каких файлах
3) риски и типичные ошибки
4) как проверить, что всё работает
Если есть варианты, дай "быстрый" и "production-ready". Как использовать
- Скопируй этот промпт и отправь в чат с ИИ.
- Прикрепи проект или открой папку репозитория в ИИ-инструменте.
- Попроси изменения по файлам, риски и короткий чеклист проверки.
В любой интеграции рано или поздно появляется одна и та же проблема. Вы отправляете запрос к API — и он не проходит. Иногда сервер отвечает ошибкой, иногда сеть даёт сбой, иногда API просто говорит: «слишком много запросов».
В логах это выглядит примерно так:
429 Too Many Requests
или
500 Internal Server Error
Если система не умеет правильно реагировать на такие ситуации, интеграция становится нестабильной:
- часть запросов падает
- данные не синхронизируются
- события теряются
- система начинает бесконечно повторять запросы
Чтобы этого не происходило, в любой серьёзной интеграции используют два базовых механизма:
rate limit и retry.
Первый отвечает за контроль скорости запросов, второй — за повторные попытки при ошибках.
Если их правильно реализовать, интеграция становится устойчивой даже при сетевых сбоях и высокой нагрузке.
Что такое rate limit
Rate limit — это ограничение на количество запросов, которые можно отправить к API за определённый промежуток времени.
Почти все публичные API используют такие ограничения.
Примеры:
- GitHub API — 5000 запросов в час
- Stripe — примерно 100 запросов в секунду
- многие SaaS — 60 запросов в минуту
Когда лимит превышен, сервер возвращает ответ:
429 Too Many Requests
Иногда вместе с дополнительным заголовком:
Retry-After: 10
Это означает, что новый запрос можно отправить только через 10 секунд.
Такие ограничения нужны для защиты инфраструктуры и справедливого распределения ресурсов между клиентами.
Почему API ограничивают запросы
На первый взгляд может показаться, что rate limit — это просто неудобство для разработчиков. Но у этого механизма есть важные причины.
Первая причина — защита сервера. Если один клиент отправит тысячи запросов в секунду, это может перегрузить систему.
Вторая причина — равномерное использование ресурсов. Ограничения гарантируют, что один пользователь не займёт всю мощность сервиса.
Третья причина — безопасность. Rate limit помогает защищаться от brute force и других атак.
Что происходит без контроля rate limit
Представим простую интеграцию, которая отправляет данные в API.
Код может выглядеть так:
for (const event of events) {
await api.send(event)
}
Если событий немного — всё работает нормально. Но если их становится тысячи, система начинает отправлять огромное количество запросов.
В какой-то момент API начинает отвечать ошибкой:
429 Too Many Requests
Если код не умеет корректно обрабатывать такие ответы, интеграция начинает работать всё хуже:
- запросы падают
- система перегружает API
- часть данных теряется
Поэтому важно контролировать скорость отправки запросов.
Что такое retry
Retry — это повторная попытка выполнить запрос после ошибки.
Смысл retry в том, что многие ошибки являются временными.
Например:
- сервер был перегружен
- балансировщик вернул ошибку
- сеть на секунду оборвалась
В таких случаях повторный запрос часто проходит успешно.
Типичные ошибки, при которых используется retry:
500 Internal Server Error502 Bad Gateway503 Service Unavailabletimeout
Во всех этих ситуациях повторная попытка имеет смысл.
Когда retry делать не нужно
Некоторые ошибки означают, что запрос никогда не станет успешным, пока не изменятся данные.
Например:
400 Bad Request401 Unauthorized403 Forbidden404 Not Found
Если повторять такие запросы, система будет просто создавать лишнюю нагрузку.
Поэтому retry должен применяться только к временным ошибкам.
Проблема наивного retry
Самая простая реализация retry выглядит так:
try {
await api.request()
} catch (e) {
await api.request()
}
Но такой подход может привести к серьёзной проблеме.
Если сервер уже перегружен, мгновенные повторные запросы только увеличат нагрузку. В результате система может попасть в состояние, когда тысячи клиентов одновременно начинают повторять запросы.
Это называют retry storm — шторм повторных запросов.
Чтобы этого избежать, используют более аккуратный алгоритм.
Exponential backoff
Один из самых популярных алгоритмов retry — exponential backoff.
Его идея очень проста: каждая следующая попытка выполняется с увеличивающейся задержкой.
Например:
1 попытка — сразу 2 попытка — через 1 секунду 3 попытка — через 2 секунды 4 попытка — через 4 секунды 5 попытка — через 8 секунд
Это даёт серверу время восстановиться и резко снижает нагрузку.
Пример retry на JavaScript
Простейшая реализация retry с exponential backoff:
async function requestWithRetry(fn, retries = 5) {
for (let attempt = 0; attempt < retries; attempt++) {
try {
return await fn()
} catch (error) {
if (attempt === retries - 1) {
throw error
}
const delay = 2 ** attempt * 1000
await new Promise(resolve => setTimeout(resolve, delay))
}
}
}
Использование:
await requestWithRetry(() => fetch("https://api.example.com"))
Если запрос завершится ошибкой, функция автоматически попробует снова.
Ограничение скорости запросов
Помимо retry, часто нужно контролировать скорость отправки запросов.
Самая простая схема — использовать очередь.
Сначала задачи попадают в очередь, затем worker отправляет их в API с контролируемой скоростью.
Простейший limiter может выглядеть так:
class RateLimiter {
constructor(limit, interval) {
this.limit = limit
this.interval = interval
this.queue = []
this.active = 0
}
async schedule(task) {
return new Promise(resolve => {
this.queue.push({ task, resolve })
this.run()
})
}
run() {
if (this.active >= this.limit || this.queue.length === 0) return
const { task, resolve } = this.queue.shift()
this.active++
task().then(result => {
resolve(result)
setTimeout(() => {
this.active--
this.run()
}, this.interval)
})
}
}
Такой limiter позволяет отправлять, например, не больше 5 запросов в секунду.
Как это выглядит в реальной архитектуре
В production системах схема обычно выглядит так:
- события попадают в очередь
- worker берёт задачу
- rate limiter контролирует скорость
- отправляется API-запрос
- при ошибке включается retry
Такая архитектура позволяет системе:
- не превышать лимиты API
- корректно обрабатывать временные ошибки
- не терять данные при сетевых сбоях.
Итог
Rate limit и retry — это фундамент любой надёжной интеграции.
Rate limit контролирует скорость запросов и защищает API от перегрузки. Retry помогает системе автоматически восстанавливаться после временных ошибок.
Даже простая реализация этих механизмов значительно повышает устойчивость интеграций и предотвращает потерю данных при работе с внешними сервисами.