Collector daemon, FastAPI server (addresses, diff, collect, sources), SQLite storage with change journal, Docker Compose deployment, tests, documentation and project rules. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
28 lines
4.9 KiB
Markdown
28 lines
4.9 KiB
Markdown
# Итоги: хранение собранных адресов в SQLite
|
||
|
||
План: `docs/plan-sqlite-storage.md`.
|
||
|
||
## Сделано
|
||
- **`db.py` (новый)**: SQLite (`ripe.db`, WAL), таблица `addresses(kind, source, value, first_seen, last_seen)`, `user_version`; `connect`/`session`/`transaction`, `merge_source` (upsert + TTL), `sweep_unconfigured`, `purge_source`, `get_values`, `count_values`.
|
||
- **Миграция**: при первом открытии базы `data.json` и `fqdn_data.json` импортируются одной транзакцией (`BEGIN IMMEDIATE`, параллельный старт безопасен), `first_seen`/`last_seen` сохраняются (старый формат без них: `last_seen` = момент миграции); оригиналы переименовываются в `*.migrated-<ts>` (резервная копия и путь отката).
|
||
- **`cidr_collector.py`**: сбор пишет в БД одной транзакцией (конфиг перечитывается внутри неё, удалённый во время сбора источник не воскресает); удалены JSON-хранилище, `merge_entry`, `purge_entry`, файловые блокировки данных. Блокировка конфига (`update_config`) осталась.
|
||
- **`api_server.py`**: чтение адресов, счётчики `/health` и `purge` работают через БД; `sqlite3.Error` и `StorageError` -> 503.
|
||
- **Порча базы**: `not a database`/`malformed` -> файл (с `-wal`/`-shm`) переименовывается в `ripe.db.corrupt-<ts>`, `StorageError` (503); `database is locked` не считается порчей и файл не трогает.
|
||
- **Развёртывание**: `db.py` добавлен в `Dockerfile`; `*.db`, `*.db-wal`, `*.db-shm`, `*.migrated-*` в `.gitignore`/`.dockerignore`; README: раздел 9 (схема, миграция, откат, бэкап), обновлены логика сбора и раздел Docker.
|
||
- **Тесты**: тесты на JSON переведены на БД, добавлены проверка порчи базы (в существующем тесте) и `tests/test_db.py` (импорт старого/нового формата, идемпотентность). Всего 14, в контейнере 14 passed.
|
||
|
||
## Проверка
|
||
- **Эталон**: на копии реальных данных ответы `/addresses?type=all|cidr|fqdn` после миграции побайтно совпадают со снятыми старой JSON-версией; повторный старт ничего не импортирует.
|
||
- Сбор: 6 ASN и 3 FQDN обновлены, повторный запуск дубликатов не создаёт (49 = 49 уникальных).
|
||
- Конкурентность: 60 запросов `/addresses` во время сбора - все 200; 15 прогонов по 5 процессов, одновременно мигрирующих чистую копию, - без ошибок, ровно один импорт.
|
||
- Порча: мусор в `ripe.db` -> 503, файл убран в `*.corrupt-*`.
|
||
- Docker Compose (два контейнера, один том): миграция в томе, эталон совпал, демон записывает, API читает, `purge` виден, после `down`/`up` данные на месте; стенд убран.
|
||
|
||
## Замечания
|
||
- После порчи базы следующие запросы вернут пустой список (создаётся новая пустая база), пока сборщик не наполнит её заново; повреждённый файл сохранён как `*.corrupt-*`. Это осталось прежним поведением, автоматического восстановления из копии нет.
|
||
- Резервное копирование не автоматизировано (в README описана команда `sqlite3 ".backup"`), это можно добавить заданием демона.
|
||
- Сообщение лога «... data saved» теперь пишется после каждой транзакции, даже если ничего не изменилось.
|
||
- Первый запуск на реальных данных: запись `google.com` (нет в конфигурации) станет стареть по TTL, её адрес удалится через 90 дней после миграции; `last_seen` старых записей после миграции = момент миграции.
|
||
- WAL не рекомендуется на сетевых ФС.
|
||
- Хранение истории изменений и `?since=` в этот шаг не входили; схема (`first_seen`/`last_seen`) для них подготовлена.
|