feat(db): pre-migration SQLite snapshots via VACUUM INTO
Take a consistent, atomic copy of the DB at lifespan startup BEFORE migrations run, so a botched future upgrade is recoverable by restoring a single file instead of a data-loss incident. Uses SQLite's VACUUM INTO — safe under WAL, cannot tear against concurrent writes. Best-effort: failures are logged, never raised — the main DB remains the source of truth. Configurable via NOTIFY_BRIDGE_PRE_MIGRATE_SNAPSHOT_KEEP (default 5; 0 disables). Snapshots land in ``data_dir/backups/pre-migrate-<ts>.db`` and the N oldest are pruned each boot.
This commit is contained in:
@@ -70,6 +70,12 @@ class Settings(BaseSettings):
|
||||
event_log_retention_days: int = 30
|
||||
"""Days of event_log history to retain. 0 disables the retention job."""
|
||||
|
||||
pre_migrate_snapshot_keep: int = 5
|
||||
"""Number of pre-migration DB snapshots to keep in ``data_dir/backups/``.
|
||||
0 disables snapshotting entirely. Each snapshot is produced at boot
|
||||
before migrations run using SQLite's ``VACUUM INTO`` (atomic, consistent).
|
||||
"""
|
||||
|
||||
model_config = {"env_prefix": "NOTIFY_BRIDGE_"}
|
||||
|
||||
def model_post_init(self, __context: Any) -> None:
|
||||
@@ -102,6 +108,8 @@ class Settings(BaseSettings):
|
||||
raise ValueError("port must be in range 1..65535")
|
||||
if self.event_log_retention_days < 0:
|
||||
raise ValueError("event_log_retention_days must be >= 0")
|
||||
if self.pre_migrate_snapshot_keep < 0:
|
||||
raise ValueError("pre_migrate_snapshot_keep must be >= 0")
|
||||
|
||||
@property
|
||||
def effective_database_url(self) -> str:
|
||||
|
||||
Reference in New Issue
Block a user