automatic DB maintenance: log rotation, orphan cleanup, VACUUM
The existing daily cleanup never effectively ran: it was an interval job counted from container start (reset on every deploy), it called asyncio.get_event_loop() from a worker thread, and even when deleting, SQLite never returns freed pages to the filesystem. Live DB: 4.1 GB, of which 2.6 GB log and 0.6 GB unused pages. New maintenance service, scheduled daily at MAINTENANCE_HOUR_UTC:30 and once 5 minutes after every start: - delete log entries older than LOG_RETENTION_DAYS (30) and keep at most LOG_MAX_ENTRIES (200k) newest ones - delete processed_mails markers of deleted rules/accounts (FKs are not enforced by SQLite) - VACUUM when >25% of the file is unused, only if free disk space covers the copy; never runs twice in parallel GET/POST /api/logs/maintenance expose status and a manual run; the log menu shows DB size, entry count and last run, with "Datenbank aufräumen & verkleinern". Removed the dead cleanup_old_logs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ from sqlalchemy.orm import Session
|
||||
|
||||
from app.database import engine, get_db
|
||||
from app.models.db_models import FilterLog, LogLevel
|
||||
from app.services.maintenance import db_status, run_maintenance
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -134,6 +135,23 @@ def get_logs(
|
||||
}
|
||||
|
||||
|
||||
@router.get("/maintenance")
|
||||
def maintenance_status():
|
||||
"""Größe der Datenbank, Anzahl Einträge und Ergebnis der letzten Wartung."""
|
||||
return db_status()
|
||||
|
||||
|
||||
@router.post("/maintenance")
|
||||
def maintenance_run(vacuum: bool = False):
|
||||
"""Wartung sofort ausführen (Log-Rotation, verwaiste Marker, ggf. VACUUM).
|
||||
vacuum=true erzwingt das Verkleinern der Datei."""
|
||||
try:
|
||||
result = run_maintenance(force_vacuum=vacuum)
|
||||
except Exception as e:
|
||||
raise HTTPException(500, f"Wartung fehlgeschlagen: {e}")
|
||||
return {"result": result, "status": db_status()}
|
||||
|
||||
|
||||
@router.delete("/")
|
||||
def clear_logs(account_id: int | None = None, db: Session = Depends(get_db)):
|
||||
"""Löscht Logs. Ohne account_id: schnelles Drop+Recreate der Tabelle
|
||||
|
||||
Reference in New Issue
Block a user