Daemon job "backup" (online copy, quick_check, rotation), restore of the newest valid copy when the database cannot be opened, change journal reset after restore, last_restore in /health, docs and tests. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
4.8 KiB
4.8 KiB
Итоги: резервные копии базы и автовосстановление (доработка Б)
План: docs/plan-db-backup.md.
Сделано
- Задание
backupв демоне (collector_daemon.py): третье задание рядом сasnиfqdn(то же расписание, защита от наложения, состояние вstatus.json); по умолчанию30 4 * * *, меняется вschedule.backupили черезPOST /schedule(type: backup). РеестрCOLLECTORSтеперь хранит вызываемые объекты, существующие тесты не менялись. - Копия (
db.backup_database): онлайн-копия средствами SQLite,quick_checkживой базы и копии, запись через*.tmpи переименование, ротация (backup_keep, по умолчанию 7) только после успешной новой. Если проверка не пройдена, копия не создаётся, старые остаются,/healthпоказываетdegraded. - Автовосстановление (
db.connect->_recover): порченая база уходит в*.corrupt-*, на её место встаёт самая свежая копия, прошедшая проверку (битые копии пропускаются); под файловой блокировкой, с повторной проверкой внутри (гонка API и демона). Без исправных копий прежнее поведение (StorageError, 503). - Журнал diff после отката: журнал очищается, счётчик сдвигается на 1 000 000, горизонт на момент восстановления: все выданные ранее курсоры и времена дают
410. - Заметность: лог ERROR, файл
last_restore.json, полеlast_restoreв/health. - Прочее:
RIPE_BACKUP_DIR(по умолчанию<DATA_DIR>/backups),backups/иlast_restore.jsonв.gitignore/.dockerignore,POST /scheduleпринимаетbackup. - README: расписание и
backup_keep, раздел «Backup and automatic restore» (вынос копий с тома, ручное восстановление),last_restoreв/health. - Тесты: 2 новых (копия, ротация и проверка; восстановление с пропуском битой копии, сброс курсоров, работа после отката, случай без копий). Всего 20, в контейнере 20 passed.
Проверка
- Отдельные процессы (демон с
backupраз в минуту иbackup_keep=2, API): скопировано и ротировано до двух файлов; после записи мусора вripe.dbAPI поднял базу из копии,/addressesвернул данные,/healthпоказалlast_restore, карантинный файл сохранён; новый курсор принимается (200). - Docker Compose (отдельный проект, порт 18000, стенд убран): расписание
backupвыставлено черезPOST /schedule, копия появилась в/data/backups, порча базы в томе привела к восстановлению, оба сервисаhealthy.
Замечания
- Копии по умолчанию лежат на том же томе, что и база: это защита от порчи файла, но не от потери тома.
- Автоматически восстанавливается только порча, видимая при открытии; порча внутри файла даёт 503, её замечает задание
backup, восстановление ручное (порядок в README). - Сдвиг журнала на 1 000 000 - эвристика: старый курсор мог бы совпасть с новой историей, только если между копиями накопится больше миллиона изменений.
- Отказ
410для старого курсора после восстановления подтверждён тестом; вручную в отдельных процессах эту проверку не повторял (команда не выполнилась из-за экранирования в оболочке). - Не сделано: копии вне сервера, шифрование, команда CLI
restore, ручной запуск копии черезPOST /collect.