Collectors record the result of every source (schema v3, table source_status); /health reports failing sources (failures in a row >= source_failure_threshold) and turns degraded; GET /sources shows the full state; runs end with a summary log line instead of "data saved". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
25 lines
5.2 KiB
Markdown
25 lines
5.2 KiB
Markdown
# Итоги: наблюдаемость (сбои источников, здоровье, логи)
|
||
|
||
План: `docs/plan-observability.md`. Закрывает наблюдения 2 и 5 анализа (`analysis-2026-09-21.md`). **Метрики Prometheus не входили** (решение пользователя).
|
||
|
||
## Сделано
|
||
- **Состояние источников (`db.py`):** схема версии 3, таблица `source_status(kind, source, last_attempt, last_success, failures, error_kind)`; автоматическая миграция 2 -> 3. Функции `record_source_result`, `forget_unconfigured`, `source_statuses`, `address_counts`; `purge_source` удаляет и состояние. Запись идёт в той же транзакции, что и данные.
|
||
- **Сборщики (`cidr_collector.py`):** результат по каждому источнику при каждом запуске (успех обнуляет `failures`, сбой увеличивает, `last_success` при сбое не меняется); `classify_error` даёт категорию без деталей (`timeout`, `connection`, `http_429/4xx/5xx`, `invalid_response`, `dns`, `no_global_addresses`, `unknown`); состояние удалённых из конфигурации источников очищается при очередном сборе; порог `failure_threshold` (`source_failure_threshold`, по умолчанию 3).
|
||
- **`/health` (`api_server.py`):** блок `sources` (по типам: `total` и только неисправные), `degraded` при неисправных источниках; остальные поля не менялись. **`GET /sources`:** все настроенные источники с числом адресов, временем попытки и успеха, сбоями и категорией.
|
||
- **Логи:** итоговая строка запуска («ASN collection finished: 6 sources, 5 ok, 1 failed, +12/-3 prefixes», для FQDN так же); сообщения «data saved» убраны (наблюдение 5).
|
||
- **README:** `/health`, `/sources`, ключ `source_failure_threshold`, схема базы, лог.
|
||
- **Тесты:** 2 новых (сборщики: запись успеха и сбоев, рост и сброс счётчика, очистка удалённого источника, категории ошибок и миграция с версии 2; API: `ok` до порога и `degraded` после, ответ без текста ошибки, `/sources`, настройка порога). Всего 30, в контейнере 30 passed.
|
||
|
||
## Проверка
|
||
- **Миграция:** база версии 2, созданная кодом до изменения (`SCHEMA_VERSION = 2` в предыдущем коммите), открыта новым кодом: `user_version` 3, все адреса и журнал на месте, состояние источников пусто.
|
||
- **Отдельные процессы:** демон с подменённым адресом RIPEstat (локальный сервер отвечает 503) и API: после первых двух запусков `/health` `ok`, после третьего `degraded` с `{"source": "62041", "failures": 3, "error_kind": "http_5xx"}`; `/sources` показывает 0 адресов и 3 сбоя; после «починки» сервера `ok`, 1 адрес, `failures: 0`. В логе итоговые строки запусков, сообщений «data saved» нет.
|
||
- **Docker Compose** (отдельный проект, порт 18000, стенд убран): FQDN `example.com` и `nonexistent.invalid`; после трёх ручных сборов `degraded`, неисправный `nonexistent.invalid` с `error_kind: dns`, `example.com` с 4 адресами; оба сервиса `healthy`.
|
||
- В первом запуске проверки миграции сценарий упал на моей опечатке (обращение к закрытой сессии после записи), сама миграция прошла; версию «до» подтвердил по коду предыдущего коммита.
|
||
|
||
## Замечания
|
||
- Порог 3 при суточном расписании FQDN означает три дня до `degraded`; порог настраивается (`source_failure_threshold`).
|
||
- Пустой корректный ответ RIPEstat считается успехом: такой источник виден в `/sources` по `addresses: 0`, но `degraded` не вызывает.
|
||
- Категория `no_global_addresses` считается сбоем: имя, разрешившееся только в частные адреса при выключенном `allow_non_global_ips`, через три запуска даст `degraded`.
|
||
- `/health` по-прежнему отвечает HTTP 200 при `degraded`; Docker healthcheck из-за внешних сбоев контейнеры не перезапускает.
|
||
- Не вошло: Prometheus, уведомления и алерты, свежесть резервных копий как признак здоровья, команда CLI `status`.
|