Ограничения частоты

Runnev применяет два независимых лимита: частоту запросов и пропускную способность публикации. Оба сообщаются в каждом ответе, чтобы вы могли регулировать темп до того, как вас притормозят.

Лимиты

Тип ключаЧастота запросовПропускная способность публикацииОбласть
Боевой (rnv_live_)1000 запр. / мин60 МиБ / минНа проект
Тестовый (rnv_test_)120 запр. / мин6 МиБ / минНа проект
Публичный демо-ключ60 запр. / минтолько подпискаНа IP

Оба лимита — это token bucket, которые пополняются непрерывно, поэтому короткий всплеск выше поминутной цифры допустим, пока среднее остаётся ниже неё.

Заголовки

Каждый ответ сообщает состояние корзины частоты запросов:

заголовки ответа
x-ratelimit-limit: 1000
x-ratelimit-remaining: 998
x-ratelimit-reset: 1785931200

x-ratelimit-reset — это время Unix, к которому корзина, как ожидается, снова заполнится. Когда вас притормаживают, 429 добавляет retry-after:

429 Too Many Requests
retry-after: 2
x-ratelimit-limit: 1000
x-ratelimit-remaining: 0
x-ratelimit-reset: 1785931200

Как пополняется корзина

Боевой ключ получает 1000 токенов и пополняется со скоростью 1000 / 60 ≈ 16,7 токена в секунду. Каждый запрос стоит один токен. Если вы потратите все 1000 в первую секунду, то дальше будете получать примерно один запрос каждые 60 мс, пока не перестанете долбить. Разбор примера: отправьте 1000 запросов мгновенно, и 1001-й будет отклонён с retry-after: 1; подождите секунду — и снова доступно около 16 токенов.

Подписки и бюджет запросов

Подписка стоит один запрос в момент подключения и ничего — далее. Удержание её открытой, сколь угодно долго, не опустошает корзину. Это намеренное проектное решение: продукт рассчитан на соединения, живущие часами, поэтому списывать их посекундно с лимита частоты не имело бы смысла. Считается только начальный GET.

Рекомендованный клиентский backoff

При 429 соблюдайте retry-after, если он есть. Иначе, а также при 5xx, отступайте экспоненциально с полным джиттером:

backoff с полным джиттером
base, cap = 0.2, 20.0            # секунды
delay = min(cap, base * (2 ** attempt))
sleep = random.uniform(0, delay) # полный джиттер: любое значение из [0, delay]

Полный джиттер (равномерный выбор из [0, delay]) разводит «стадо» куда лучше фиксированного экспоненциального расписания, где все клиенты повторяют в один и тот же миг. Все три SDK это реализуют.

Как оставаться под лимитом

Лимит частоты запросов считает запросы, а не события, поэтому группировка событий в пакеты — это способ передать больше данных, не упираясь в него. При боевом лимите 1000 запр./мин одно событие на запрос ограничивает вас примерно 16 событиями/с; сто событий на запрос поднимают это примерно до 1600 событий/с при том же самом лимите. Тогда связывающим ограничением становится лимит пропускной способности 60 МиБ/мин, который считает байты публикации. О компромиссе размера см. Группировка пакетов ради пропускной способности.