Files
ripe-cidr-collector/docs/summary-review-fixes-5-10.md
T
ayurishchevandClaude Sonnet 5 aaf41adc79 Stage B of review fixes: daemon state lock, image build check, RIPEstat retries
Job state is changed under one RLock, the Dockerfile copies all root
modules and imports them at build time, RIPEstat requests go through a
retrying session with the sourceapp parameter (ripestat_sourceapp) and a
capped Retry-After. Adds the summary and marks review findings 5-10 fixed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 10:12:48 +03:00

5.2 KiB
Raw Blame History

Итоги: исправления 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.