Мок-API
Лимиты
Как шлюз эмулирует лимиты боевых API: дырявое ведро, burst, разные коды превышения и то, у кого из сервисов вообще есть заголовки лимита.
На этой странице · 6
Лимиты в песочнице — эмуляция поведения боевого API, а не защита APIStend. Смысл в том, чтобы код, который в бою упрётся в лимит, упёрся в него и на стенде, и обработал это правильно: у Bitrix24 — по коду 503, у остальных — по 429.
Схема: дырявое ведро
У каждой пары «ключ + сервис» своё ведро — а у Apify на каждый класс путей
своё, см. ниже. Ёмкость — burst; ведро пополняется
плавно, со скоростью limit запросов за windowMs. Запрос забирает один токен;
если токенов нет — превышение.
Профили лимитов
Ведро — не украшение. Без него мок оказался бы в двадцать пять раз строже
боевого Bitrix24: приложение, которое при старте вызывает app.info,
profile и placement.bind, получало бы 503 на третьем вызове.
У Apify лимит принадлежит методу, а не сервису
Единственный сервис в стенде, где одного числа мало. Документация Apify называет
базовые 60 запросов в секунду на ресурс, 200 на записи key-value store и 400 на
запуски и датасеты; живой ответ /v2/users/me добавляет к этому 90 на профиль
пользователя.
Вёдра у классов раздельные, поэтому упереться в лимит на датасетах, не тронув остальные вызовы, здесь можно так же, как в бою. Один общий лимит на сервис означал бы, что клиент, читающий заголовок на датасете, увидит 60 вместо 400 и построит свой троттлинг всемеро строже боевого.
Глобальный потолок Apify — 250 000 запросов в минуту на пользователя — мок не воспроизводит: до него не доберётся никакая отладочная нагрузка, а ведро на четверть миллиона токенов означало бы держать состояние ради события, которое не наступит.
Как это выглядит
Пятьдесят один запрос подряд к Bitrix24 проходит, дальше — 503:
for i in $(seq 1 60); do
curl -s -o /dev/null -w "%{http_code} " -X POST \
localhost:8080/b24/rest/crm.deal.fields.json -H "X-Mock-Key: $KEY" -H "X-Mock-Delay: 0"
done
# 200 200 … 200 503 503 503 503 503 503 503 503 503
HTTP/1.1 503 Service Unavailable
content-type: application/json; charset=utf-8
x-apistend-retry-after: 1
x-apistend-scenario: rate_limit
{"error":"QUERY_LIMIT_EXCEEDED","error_description":"Too many requests"}
Пятьдесят первый запрос проходит потому, что ведро успевает пополниться: пока идут пятьдесят запросов, набегает доля секунды и в ведро возвращается токен-другой.
У Bitrix24 это 503, а не 429
Самая частая ошибка в обработке лимита Bitrix24 — ловить 429. Портал при
превышении отвечает 503 QUERY_LIMIT_EXCEEDED и не присылает Retry-After;
интервал повтора клиент выбирает сам. Мок повторяет это буквально.
Заголовки лимита есть не у всех
Это первое, что ломает ожидания: единого набора заголовков у сервисов нет, и APIStend не приписывает их тем, у кого их не бывает.
В X-Ratelimit-Limit стоит ёмкость ведра, а не средняя скорость: клиент по
этому числу считает, сколько запросов может отправить сразу. X-Ratelimit-Reset —
через сколько секунд ведро наполнится целиком, X-Ratelimit-Retry — через сколько
разрешён следующий запрос.
Рекомендуемую паузу там, где боевой сервис её не сообщает, шлюз отдаёт своим
заголовком X-APIStend-Retry-After. Он начинается с x-apistend-, и это
сознательно: чужой заголовок подделывать нельзя, а подсказать — можно.
Не пишите обработку лимита по заголовкам Wildberries для всех трёх
Код вида «прочитать X-Ratelimit-Retry и поспать столько секунд» на Ozon
и Bitrix24 не сработает ни на стенде, ни в бою: заголовка там нет. Для них
нужен собственный откат — экспоненциальный или по time.operating_reset_at
у Bitrix24.
Проверить обработку, не расходуя ведро
Тесту редко нужен настоящий перебор лимита: достаточно, чтобы код увидел ответ о превышении. Для этого есть сценарий:
curl -i localhost:8080/wb/api/v3/warehouses \
-H "X-Mock-Key: $KEY" -H "X-Mock-Scenario: rate_limit"
Ответ будет тот же, что и при настоящем превышении, — включая коды и заголовки.
Подводные камни
- Ведро считается на ключ и сервис по отдельности. Два ключа одной песочницы — два независимых ведра; исчерпать лимит Ozon, стуча в Bitrix24, нельзя.
- У локального приложения Bitrix24 ведро своё — на приложение, а не на ключ.
- Счётчик живёт в памяти процесса. После перезапуска API все вёдра полные; на нескольких инстансах лимит считается на каждом отдельно.
- Токен тратится на любом запросе, включая тот, что закончится 404 или
ошибкой авторизации, и включая запрос с
X-Mock-Scenario. - Порядок такой: сначала лимит, потом сценарий. Если ведро пусто, заказанный
заголовком сценарий уступает место
rate_limit. - Отдельно от этого существует лимит Management API (
/api/v1/…) — он ограничивает нагрузку на сам APIStend и к эмуляции боевых лимитов отношения не имеет.