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

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

Co-authored-by: Cursor <cursoragent@cursor.com>
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

+22 -7
View File
@@ -14,14 +14,14 @@
|----------|------|
| `evobgp-api` | Только HTTP API и связанная логика в одном процессе. |
| `evobgp-all` | Тот же API + in-process **scheduler** (очередь `module_refresh` в общем Registry), **ingest** (prefetch ETag CDN), **render** (опционально auto-publish), **deploy** (лог расхождений published/applied). |
| `evobgp-scheduler` | По `refresh_interval_sec` ставит refresh: в одном процессе с API — через `jobs.Registry`; в reference Compose — **HTTP** `POST /v1/modules/{id}/refresh` (`EVOBGP_CONTROL_PLANE_URL`, `EVOBGP_SCHEDULER_BEARER`). |
| `evobgp-scheduler` | По `refresh_interval_sec` ставит tenant refresh. Reference Compose: доверенный DB-worker, общая PostgreSQL queue (`EVOBGP_SCHEDULER_MODE=db`). Опциональный HTTP-режим ограничен явным tenant; параметры и Compose override описаны в quickstart. |
| `evobgp-ingest` | Периодический conditional GET по URL CDN-источников и обновление `etag` в БД. |
| `evobgp-render` | По умолчанию только heartbeat; при `EVOBGP_RENDER_AUTOPUBLISH=1` выставляет всем спикерам tenant последнюю ревизию (упрощение для демо). |
| `evobgp-deploy` | Периодически логирует **drift**: `last_applied_revision_id` vs опубликованная ревизия для ноды. |
| `evobgp-node` | CLI реплики: `pull-bundle`, `verify-bundle`, `apply-bundle`. |
| `evobgp-agent` | Локальный агент рядом с BIRD: `watch`, **`serve`** (Panel→Node sync API на реплике). |
В Docker Compose профиль **reference** запускает отдельные контейнеры под `evobgp-api` и четыре воркера; профиль **microvps** использует один контейнер `evobgp-all`.
В Docker Compose профиль **reference** запускает отдельные контейнеры под `evobgp-api` и четыре воркера; профиль **microvps** использует один контейнер `evobgp-all`. Сервис NATS вынесен в отдельный профиль `nats` и не требуется для внутренней очереди задач.
## Пакеты `internal/` (сжатая карта)
@@ -31,14 +31,15 @@
| `store` | Абстракция бэкенда данных; реализации в памяти и через репозиторий. |
| `repository` | Доступ к PostgreSQL, сущности и миграции на уровне приложения. |
| `db` | Подключение к БД и применение миграций. |
| `jobs` | Реестр и выполнение асинхронных задач, связанных с API. |
| `jobs` | Durable enqueue/claim, lease/heartbeat/fencing, выполнение задач и deployment reconciliation. |
| `telemetry` | Ограниченный фоновый collector legacy BGP/health и local BIRD; persistent snapshots и fenced discovery. |
| `bundle` | Упаковка и проверка бандлов для нод. |
| `signing` | Криптографическая проверка подписей. |
| `birdfmt` | Форматирование и фрагменты конфигурации BIRD, вызовы `birdc`. |
| `birddeploy` | Логика применения конфигурации к BIRD (используется в цепочке деплоя). |
| `config` | Переменные окружения `EVOBGP_*`. |
| `observability` | Метрики Prometheus, HTTP middleware. |
| `broker` | Опциональный `EVOBGP_BROKER_URL` для будущей шины; сейчас задачи только in-process (`jobs.Registry`), пакет лишь логирует факт настройки URL. |
| `broker` | Опциональный `EVOBGP_BROKER_URL` для будущей шины; пакет лишь логирует URL, NATS не участвует в исполнении задач. Текущий Registry дополнен PostgreSQL persistence/claim/reclaim. |
| `pipeline` | Ingest+render для `module_refresh`: CDN/AS/IP/DOMAINS → `module_prefix_snapshot` (batch `COPY`, per-module lock) → агрегация CIDR O(n log n) → `CreateRenderRevision`. Fast-path снапшота — `module.input_hash`; DoH — TTL-кэш `domain_resolve_cache`; scheduler — jitter границ интервала. |
| `nodedispatch` | Panel→Node HTTP wake-up (`POST /v1/agent/sync`) после `deploy_apply`. |
| `agentserver` | HTTP API на реплике (`serve`): sync + health для Traefik; опционально firewall failover (`/v1/firewall/*`). |
@@ -71,7 +72,7 @@ flowchart LR
Operator --> API
NodeCLI --> API
API --> PG
Sched -->|HTTP_or_DB| API
Sched -->|optional_single_tenant_HTTP| API
Sched --> PG
Ingest --> PG
Render --> PG
@@ -79,7 +80,21 @@ flowchart LR
Agent --> BIRD
```
Очередь задач по-прежнему **in-memory в процессе API** (`jobs.Registry`); отдельный контейнер `evobgp-scheduler` не разделяет память с API и дергает refresh по HTTP. Полноценный брокер (NATS) и общая очередь `job_audit` между процессами — в следующих итерациях.
При PostgreSQL очередь использует общий `job_audit`: enqueue фиксируется до HTTP `202`, claim получает owner/lease/fencing token, а heartbeat продлевает владение. List/get/cancel/report читают общее хранилище. `Server.StartBackground` запускает durable queue и deployment reconciliation; Memory-режим сохраняет задания только в процессе. Подробности и ограничения — [durable-jobs.md](durable-jobs.md). NATS не участвует в исполнении задач. Разрыв между сохранением CRUD и автоматическим enqueue пока не закрыт transactional outbox; ошибка постановки явно сообщается клиенту.
### Фоновая статистика
`Server.StartBackground` также запускает `telemetry.Collector`. Фиксированное число workers получает due targets из store с lease/fencing, опрашивает прежние endpoints агента 2.56.2 и локальный BIRD, затем сохраняет независимые BGP/health результаты. Discovery записывается в той же fenced транзакции. Истёкший владелец не может заменить snapshot или discoveries. Конфигурация speaker проверяется перед фиксацией; смена endpoint/секрета не переносит успешное наблюдение прежней конфигурации на новую.
GET peers/speakers/discoveries читает сохранённое состояние; `live=1` не вызывает сетевой fan-out. POST `/v1/telemetry/refresh` объединяет запросы в пределах 10 секунд и назначает следующий сбор. `received_at` и настроенный интервал определяют свежесть, `expires_at` передаёт её срок клиенту; просроченные sessions не становятся текущим Established. При недоступности хранилища snapshots API отвечает 503.
Для local BIRD несколько CP различаются стабильной authority. `EVOBGP_TELEMETRY_LOCAL_ID` должен идентифицировать именно BIRD-узел; одинаковый ID допустим только при чтении одного экземпляра BIRD. Две одновременно актуальные authority одного master дают неизвестный статус. Устаревшая authority после перезапуска не скрывает единственный свежий снимок. Настройки интервала, workers и локальной идентичности — [quickstart.md](quickstart.md).
### Снимки префиксов модуля
`UpdateModulePrefixSnapshot` выполняет read-modify-write атомарно. В PostgreSQL transaction advisory lock, чтение текущих строк, замена снимка и `module.input_hash` используют одну транзакцию и одно соединение. Потеря соединения не позволяет продолжить запись через другое. GET читает заголовок и строки в repeatable-read транзакции; ошибки scan/iteration не превращаются в неполный успешный результат. Memory использует блокировку ключа tenant/module и фиксирует snapshot/hash под общей mutex. Callback преобразует переданный снимок и не вызывает store I/O.
Это сериализует фиксацию снимка, но ещё не гарантирует единую версию всех входов ingest: конфигурация и input hash вычисляются до транзакции, а tenant manifest/version CAS остаётся отдельной работой B04. Контекст передаётся в операции snapshot и lookup; устаревшие вызовы других store-сущностей требуют последующего расширения.
## Диаграмма: microvps (`evobgp-all`)
@@ -96,7 +111,7 @@ flowchart LR
Внутри `evobgp-all` все воркеры используют **тот же** `store` и `jobs.Registry`, что и HTTP handlers, поэтому `module_refresh` выполняется в том же процессе без HTTP.
Профиль Compose **`microvps-full`** добавляет к этому стеку **Web UI** (nginx → `evobgp-all`), **NATS** и **Prometheus** без отдельных контейнеров воркеров (функционально то же, что отдельные `scheduler`/`ingest`/… в reference). Запуск и лимиты под ~1 ГиБ RAM — в [quickstart.md](quickstart.md).
Профиль Compose **`microvps-full`** добавляет к этому стеку **Web UI** (nginx → `evobgp-all`) и **Prometheus** без отдельных контейнеров воркеров (функционально то же, что отдельные `scheduler`/`ingest`/… в reference). NATS включается отдельно через профиль `nats`. Запуск и текущие лимиты — в [quickstart.md](quickstart.md); пригодность для ~1 ГиБ RAM требует замера под нагрузкой.
## Поток pipeline (ingest → render)