Опрос и идемпотентность
Опрос — источник правды
Заголовок раздела «Опрос — источник правды»GET /serving-tasks/?status=offered — то, как вы находите работу. Webhook’и,
если зарегистрированы, являются оптимизацией задержки —
но не правдой. Опрашивайте, пока ваш парк на смене,
с той частотой, которую вам даёт Sitora.
Одна страница отдаёт не более limit задач — 50 по умолчанию, максимум 100.
На загруженной кассе предложений может быть больше, чем показывает одна
страница, поэтому поднимайте limit, а не читайте короткий список как тихую
кухню. Список доставок webhook’ов принимает тот же параметр: 100 по умолчанию,
максимум 200.
Частоту опроса задаёт Sitora
Заголовок раздела «Частоту опроса задаёт Sitora»Каждый ответ со списком задач — и 200, и 304 — сообщает, сколько секунд
подождать перед следующим запросом:
X-Sitora-Poll-After: 2Retry-After: 2Оба заголовка несут одно и то же число. Подождите столько и опрашивайте снова.
Не зашивайте интервал в код. Sitora может поднять его сразу для всех парков без вашего релиза — так проблема нагрузки решается замедлением парков, а не отказом в их трафике. Сегодня список задач просит две секунды.
Retry-After в успешном ответе — это темп, а не ошибка. 200 или 304 с этим
заголовком означает ровно то, что написано: вот ответ, и вот когда вернуться.
Heartbeat и снимок парка так не темпируются. Продолжайте слать heartbeat по своему таймеру, примерно раз в 30 секунд, как описано в heartbeat и состоянии парка.
Список задач несёт ETag. Отправляйте его обратно как
If-None-Match; неизменившийся список вернёт 304 Not Modified без тела. Это
делает плотные циклы опроса почти бесплатными для обеих сторон — реализуйте это
обязательно.
Список доставок webhook’ов ETag не несёт. Листайте его через since_id.
Лимиты частоты
Заголовок раздела «Лимиты частоты»Лимиты строгие и считаются по учётным данным:
| Поверхность | Лимит |
|---|---|
| Опрос задач | 60/минуту (~1/с) |
| Принятие/отчёт по задаче | 120/минуту |
| Heartbeat | 30/минуту |
Контроллер, которому нужно больше, ведёт себя неправильно, а не занят. 429 —
это отказ Sitora, а не темп: его Retry-After обязателен к соблюдению, а само
попадание в него означает, что ваш цикл проигнорировал заголовок частоты выше.
Идемпотентность
Заголовок раздела «Идемпотентность»Каждая мутация принимает заголовок Idempotency-Key (или поле тела
client_idempotency_key). Повторный запрос с тем же ключом возвращает исходный
результат и ничего нового не записывает.
Всегда отправляйте его. Сеть рвётся посреди запроса; с ключом вы можете свободно повторять и никогда не примените дважды принятие или отчёт.
Используйте один ключ на действие, а не один на задачу: тот же ключ для
повторов того же логического действия и новый ключ для каждого следующего. Ключ,
уже потраченный на другой переход той же задачи, отклоняется с 409
(idempotency_key_reused). Ключи ограничены 128 символами.
Тела запросов тоже ограничены — необязательные объекты telemetry и summary
в heartbeat должны быть JSON-объектами не более 4 КБ, вложенностью не более 5
уровней и не более чем с 50 записями в любом объекте или массиве.
Конверт ошибки
Заголовок раздела «Конверт ошибки»Отказ, который поднимает сама поверхность робототехники, возвращает одну форму:
{ "detail": "Понятное человеку объяснение.", "code": "machine_readable_code" }| HTTP-статус | Коды |
|---|---|
400 |
unknown_status (неизвестное значение в фильтре status), invalid_limit, invalid_since_id, unknown_failure_code |
404 |
task_not_found, delivery_not_found |
409 |
already_claimed, robotics_paused, platform_frozen, arrival_dwell_pending, idempotency_key_reused, конфликты порядка task_<current_status> |
410 |
offer_expired |
503 |
content_key_missing — эта установка Sitora сконфигурирована неверно, повтор не поможет |
Ветвитесь по code, а не по тексту detail — формулировка detail может
меняться; коды контрактны.
Отказы без code
Заголовок раздела «Отказы без code»Три отказа отвечают ещё до того, как запрос дойдёт до поверхности
робототехники, поэтому поля code у них нет. Клиент, который безусловно читает
body["code"], падает на всех трёх — читайте это поле защитно.
- Некорректное тело отклоняется валидацией поля, и тело ответа
ключуется по проблемному полю:
{"status": ["\"loaded\" is not a valid choice."]}. 401и403возвращают{"detail": "..."}.401означает, что ключ недействителен или отозван.403означает, что ключ верен, но действовать им нельзя: либо парк утратил правомочность — сертификация, активация или право по тарифу — либо у ключа нет нужного этому эндпоинту scope. Причина названа в тексте.429возвращает{"detail": "..."}с заголовкомRetry-After.