update
This commit is contained in:
39
backend/app/backup.py
Normal file
39
backend/app/backup.py
Normal file
@@ -0,0 +1,39 @@
|
||||
"""Nächtliche Kopie der Datenbank.
|
||||
|
||||
Sammlungen, Wertungen und Wünsche liegen nur in dieser einen Datei. Die
|
||||
Kopie entsteht über SQLites eigene Backup-Schnittstelle — die ist auch
|
||||
dann konsistent, wenn gerade jemand schreibt. Es bleiben die letzten
|
||||
vierzehn Stände, jeder Tag einer.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import sqlite3
|
||||
from datetime import date
|
||||
|
||||
from .config import DB_PATH
|
||||
|
||||
log = logging.getLogger("app.backup")
|
||||
|
||||
BEHALTEN = 14
|
||||
|
||||
|
||||
def sichern():
|
||||
ordner = DB_PATH.parent / "backups"
|
||||
ordner.mkdir(parents=True, exist_ok=True)
|
||||
ziel = ordner / f"{DB_PATH.stem}-{date.today():%Y-%m-%d}{DB_PATH.suffix}"
|
||||
|
||||
quelle = sqlite3.connect(DB_PATH)
|
||||
kopie = sqlite3.connect(ziel)
|
||||
try:
|
||||
quelle.backup(kopie)
|
||||
finally:
|
||||
kopie.close()
|
||||
quelle.close()
|
||||
|
||||
# Die Namen sortieren nach Datum, das Alte steht vorn
|
||||
alte = sorted(ordner.glob(f"{DB_PATH.stem}-*{DB_PATH.suffix}"))[:-BEHALTEN]
|
||||
for alt in alte:
|
||||
alt.unlink()
|
||||
|
||||
log.info("Datenbank gesichert: %s", ziel.name)
|
||||
return ziel
|
||||
@@ -10,6 +10,7 @@ from fastapi.middleware.gzip import GZipMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
from . import (
|
||||
backup,
|
||||
db,
|
||||
events,
|
||||
features,
|
||||
@@ -69,6 +70,11 @@ app.add_middleware(
|
||||
)
|
||||
|
||||
|
||||
async def sicherung():
|
||||
# Die Kopie blockiert kurz — nicht im Ereignisschleifen-Thread
|
||||
await asyncio.to_thread(backup.sichern)
|
||||
|
||||
|
||||
async def guarded_sync():
|
||||
if sync_lock.locked():
|
||||
log.info("Sync läuft bereits")
|
||||
@@ -85,6 +91,9 @@ async def startup():
|
||||
watched.init()
|
||||
wishlist.init()
|
||||
features.init()
|
||||
# Erst die Sicherung, dann der Sync — so liegt vor jedem Katalog-Update
|
||||
# ein sauberer Stand
|
||||
scheduler.add_job(sicherung, "cron", hour=4, minute=0, id="daily-backup")
|
||||
scheduler.add_job(guarded_sync, "cron", hour=4, minute=30, id="daily-sync")
|
||||
scheduler.start()
|
||||
if not db.get_meta("last_sync"):
|
||||
|
||||
Reference in New Issue
Block a user