28 lines
5.2 KiB
Markdown
28 lines
5.2 KiB
Markdown
# Итоги: исправления 5-10 по результатам ревью
|
||||
|
|
|
|||
|
|
План: `docs/plan-review-fixes-5-10.md`. Источник: `docs/review-2026-09-21.md`. Два этапа, два коммита; тестов стало 27 (было 24).
|
|||
|
|
|
|||
|
|
## Этап А: путь чтения (находки 5, 6, 10), коммит `d6b69d0`
|
|||
|
|
- **5. Один снимок в `/addresses`:** `db.read_transaction`, одна сессия вместо трёх; курсор в `X-Changes-Cursor` берётся в том же снимке, что и данные. Функции `get_cidrs`/`get_fqdn_ips` удалены.
|
|||
|
|
- **6. `/health` без путей:** в `last_restore` только `{at, backup}` (имя файла копии); каталоги, карантин и текст ошибки остаются в `last_restore.json`.
|
|||
|
|
- **10. `get_changes` пакетами:** проверка наличия порциями по `PRESENCE_BATCH = 500` вместо запроса на каждое значение; `get_changes` использует `read_transaction`.
|
|||
|
|
- **Проверка:** ответы шести запросов (`/addresses` с разными параметрами, `/addresses/diff`) до и после совпали побайтно; `get_changes(cursor=0)` на журнале из 12 тыс. записей: 6832 мс -> 88 мс; при параллельной записи пар ASN/FQDN старый код дал 303 несогласованных ответа из 411, новый - 0 из 601.
|
|||
|
|
|
|||
|
|
## Этап Б: демон, образ, внешний источник (находки 7, 8, 9)
|
|||
|
|
- **7. Состояние заданий:** `_state_lock` стал `RLock`, все изменения `job_state` (`run_job`, `schedule_jobs`, `sync_schedule`) выполняются под ним; при прерывании (`SystemExit`) прежняя `last_error` сохраняется.
|
|||
|
|
- **8. `Dockerfile`:** `COPY *.py ./` вместо списка модулей и проверка `import api_server, collector_daemon, db, healthcheck` на этапе сборки.
|
|||
|
|
- **9. RIPEstat:** сессия `requests` с повторами (до 3, при сбоях соединения и кодах 429/500/502/503/504, паузы 0, 2, 4 с), параметр `sourceapp` (по умолчанию `ripe-cidr-collector`, ключ `ripestat_sourceapp` в `config.json`), сессия создаётся на запуск сбора и закрывается в конце. После исчерпания повторов источник пропускается, ничего не удаляется.
|
|||
|
|
- **Тесты:** 2 новых (задание `backup` в демоне: регистрация, ротация по `backup_keep`; сессия RIPEstat: `sourceapp`, ключ из конфига, `None` после сбоя, настройка повторов и потолка `Retry-After`).
|
|||
|
|
- **README:** `ripestat_sourceapp`, логика повторов, проверка образа.
|
|||
|
|
|
|||
|
|
## Проверка этапа Б
|
|||
|
|
- Локальный «RIPEstat»: два ответа 503, затем 200 -> результат за 2,0 с, три запроса, в каждом `sourceapp` (значение из конфига); постоянный 429 с `Retry-After: 3600` (потолок на время проверки 1 с) -> 4 попытки за 3,0 с, источник пропущен с записью в лог.
|
|||
|
|
- Сборка образа: текущий код собирается; копия проекта без `formatters.py` не собирается (падает импорт); новый модуль в корне попадает в образ без правки `Dockerfile`.
|
|||
|
|
- Docker Compose (отдельный проект, порт 18000, стенд убран): три задания в `/health`, ручной сбор FQDN отработал, расписание `backup` изменено через API и применено демоном (копия появилась), `status: ok`, сервисы `healthy`, ошибок в логе нет.
|
|||
|
|
- Первая попытка негативной проверки образа не выполнилась (в среде нет `rsync`): повторена через `tar`.
|
|||
|
|
|
|||
|
|
## Отличия от плана и замечания
|
|||
|
|
- **Паузы 0, 2, 4 с, а не 1, 2, 4:** первая повторная попытка в `urllib3` идёт без паузы. Худший случай на один ASN около 46 с (4 попытки по 10 с и паузы).
|
|||
|
|
- **`Retry-After` не «уважается» безусловно, а ограничен потолком `MAX_RETRY_AFTER = 30` с:** иначе ответ с `Retry-After: 3600` блокировал бы сборщик на час. В худшем случае с длинным `Retry-After` один ASN займёт до 130 с.
|
|||
|
|
- `sourceapp` виден RIPE: не помещайте в него секреты; контакт администратора допустим.
|
|||
|
|
- Оставлено: архитектурные замечания ревью (вынос путей в `settings.py`, разделение `api_server.py` и `cidr_collector.py`), ограничение частоты `POST /collect`, повторные запросы DNS.
|