docs(docs): describe durable jobs, telemetry, and bundle limits

Зафиксированы очередь job, семантика метрик, лимиты бандла и исходящих запросов, а также чеклист продакшена для пула соединений.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
DenozordecandCursor committed 2026-11-02 17:24:18 +07:00
1 parent bda45d633e
commit 240d83fc61
15 files changed
+839 -17

No files matched your search

+36
View File
@@ -23,6 +23,14 @@
Все остальные запросы под **`/v1/...`**, кроме перечисленных выше трёх `GET`, проходят через middleware и требуют **`Authorization: Bearer <api_key>`** (см. [access.md](access.md)).
## Ограничение тела запроса
После аутентификации все непубличные `/v1/...` запросы проверяются целиком до вызова handler: максимум **8 MiB (8388608 bytes)**. Проверка действует для любого метода, включая GET, без зависимости от `Content-Type` или `Content-Length`; JSON с большим хвостом whitespace не позволяет выполнить мутацию до обнаружения превышения. Ответ — `413 application/problem+json`, без выполнения запрошенной мутации. Ошибка чтения возвращает `400`, отмена/таймаут чтения — `408`.
Запросы с телом допускаются без очереди ожидания: по умолчанию **4 одновременно на API instance**. `EVOBGP_API_BODY_MAX_CONCURRENT` задаёт число от 1 до 64; невалидное значение выбирает default 4. Слот удерживается до завершения handler, пока его request buffer может использоваться. При занятых слотах — немедленный `429` с `Retry-After: 1`. Пустые `http.NoBody` запросы, включая обычные node GET/pull, слота не занимают; указание `Content-Length: 0` при фактически существующем body не отключает ограничение.
CSV сохраняет отдельные ограничения своей операции: 8 MiB, 10000 строк данных, 64 поля. Тело запроса проверяется до импорта; SSE ограничивается только на входе и продолжает потоковый ответ. Предел буферов ограничивает память входящих тел, а не всю память разбора JSON, работы handler или response.
## Группы маршрутов (соответствие тегам OpenAPI)
Ниже — обзор того, что реализовано в коде (`internal/httpapi/routes.go`, `routes_crud.go`). Детали тел, кодов ответов и схем — только в OpenAPI.
@@ -65,6 +73,8 @@
- `GET|PATCH|DELETE /v1/peers/{id}`
- Для `POST|PATCH|DELETE` peer запускается быстрый job `peer_reconcile` (без module ingest/сбора префиксов); после него автоматически ставится apply на спикеры.
Live-состояние следует читать вместе с `live_observation` (схема `LiveObservation` в OpenAPI). Отсутствующее наблюдение не означает ноль сессий или отказ BGP: `session_state` может быть `null`, а сохранённое значение вынесено в `last_known_session_state`. Для назначенного пира состояние вычисляется по его speaker; успешный опрос другого узла не делает его healthy. У speakers отдельно представлены качество опроса BGP и агента; счётчики без успешного опроса nullable.
### Speakers
- `GET /v1/speakers`, `POST /v1/speakers`
@@ -86,6 +96,8 @@
- `POST /v1/speakers/{id}/apply`
- `POST /v1/bird/reload`
Ответ `202` подтверждает принятие задания. Результат доставки удалённому агенту не равен применению: старый `2xx` без явного revision ID имеет уровень `unconfirmed`; совпадающий явный ACK — `agent_reported`. Локальный успешный apply — `local_applied`. Подтверждение хеша работающего BIRD-конфига (`verified`) пока не реализовано. Job содержит частичные результаты по speakers; ошибка одного узла не скрывается общим успехом, отмена сохраняет выполненную часть и останавливает публикацию следующим узлам. Границы совместимости и одного активного deploy writer описаны в [backend-compatibility.md](backend-compatibility.md).
### Jobs
- `GET /v1/jobs`, `GET /v1/jobs/{job_id}`
@@ -161,6 +173,30 @@ curl -s -H "Authorization: Bearer opkey" http://localhost:8080/v1/modules
CORS для браузерных клиентов настраивается переменной **`EVOBGP_CORS_ORIGINS`** на стороне API.
### Квоты preview и lookup
Синхронные `GET /lookup`, CDN preview и revision preview используют общий локальный пул: по умолчанию 4 активных операции на процесс API, не более 2 на tenant. Для каждого tenant действуют отдельные минутные счётчики: 120 lookup, 30 CDN preview и 30 revision preview. При заполнении возвращается `429` с `Retry-After`, без очереди ожидания. Отмена клиента не освобождает место, пока обработчик действительно не завершил работу. `Retry-After` доступен также клиентам через CORS.
| Переменная | По умолчанию | Допустимый диапазон |
|---|---:|---:|
| `EVOBGP_API_EXPENSIVE_MAX_CONCURRENT` | 4 | 1–64 |
| `EVOBGP_API_EXPENSIVE_TENANT_CONCURRENT` | 2 | 1–64 |
| `EVOBGP_API_LOOKUP_PER_MINUTE` | 120 | 1–100000 |
| `EVOBGP_API_CDN_PREVIEW_PER_MINUTE` | 30 | 1–100000 |
| `EVOBGP_API_REVISION_PREVIEW_PER_MINUTE` | 30 | 1–100000 |
Некорректное значение заменяется значением по умолчанию. Состояние ограничено 4096 tenant; действующие счётчики и активная работа не вытесняются ради новых tenant. Квоты локальны: несколько API-реплик умножают доступную нагрузку. Они не являются общей кластерной квотой. Refresh/retry управляются отдельной durable queue с её лимитами и replay исходного запроса; legacy bundle/latest endpoints не используют квоту preview/lookup. Общий admission входного тела может вернуть `429` до проверки replay, поэтому такой POST можно повторить с тем же idempotency key.
### Ограничения CSV-импорта
CSV-импорт ограничен 8 MiB полного тела запроса, 10000 строк данных без заголовка и 64 полями в одной записи. Превышение возвращает `413` до создания записей, включая запросы без `Content-Length`; отправляйте большие списки частями. Синтаксически корректный префикс слишком большого файла больше не импортируется молча. Отмена запроса останавливает последующие записи. Ошибки данных или БД после начала импорта всё ещё могут оставить уже созданные строки: импорт не является общей транзакцией.
### Сохранённый отчёт доставки
`GET /v1/jobs/{job_id}/report` требует `bgp:operations:read` и возвращает `deployment_progress` независимо от промежуточной `meta`. Для recovery job поле `source_deployment_job_id` указывает исходную операцию в том же tenant. Пока собственных записей нет, отчёт показывает исходный прогресс; после начала recovery — собственный. Каждый элемент содержит `job_id`, поэтому происхождение результата видно явно.
`health_received_at` — время получения наблюдения control plane, `health_source_at` — необязательная отметка агента. Отсутствие этого поля у 2.56.2 не препятствует доставке. `unknown` и `unconfirmed` нельзя интерпретировать как подтверждённое применение или отказ BIRD. Полный HTTP-контракт: [OpenAPI, getJobReport](openapi.yaml).
## Связанные документы
- [access.md](access.md) — ключи и роли.