"""Data retention policies — scheduled cleanup of aged records.""" # Enable future language features for compatibility from __future__ import annotations # Import logging import logging # Import datetime, timedelta, timezone from datetime from datetime import datetime, timedelta, timezone # Import Session from sqlalchemy.orm from sqlalchemy.orm import Session # Import SessionLocal from app.database from app.database import SessionLocal # Import AuditLog from app.models.audit from app.models.audit import AuditLog # Import cleanup_old_notifications from app.services.notification_service from app.services.notification_service import cleanup_old_notifications # Assign logger = logging.getLogger(__name__) logger = logging.getLogger(__name__) # Assign AUDIT_LOG_RETENTION_DAYS = 730 AUDIT_LOG_RETENTION_DAYS = 730 # Define function apply_retention_policies def apply_retention_policies(db: Session) -> dict[str, int]: """Apply retention rules. Commits the session before returning.""" # Assign cutoff = datetime.now(timezone.utc) - timedelta(days=AUDIT_LOG_RETENTION_DAYS) cutoff = datetime.now(timezone.utc) - timedelta(days=AUDIT_LOG_RETENTION_DAYS) # Assign deleted_audit = ( deleted_audit = ( db.query(AuditLog) # Chain .filter() call .filter(AuditLog.timestamp < cutoff) # Chain .delete() call .delete(synchronize_session=False) ) # Check: deleted_audit if deleted_audit: # Log info: logger.info( # Literal argument value "Retention: deleted %d audit logs older than %d days", deleted_audit, AUDIT_LOG_RETENTION_DAYS, ) # Assign deleted_notifications = cleanup_old_notifications(db, days=90) deleted_notifications = cleanup_old_notifications(db, days=90) # Commit all pending changes to the database db.commit() # Return { return { # Literal argument value "audit_logs_deleted": deleted_audit, # Literal argument value "notifications_deleted": deleted_notifications, } # Define function run_retention_job def run_retention_job() -> None: """Entry point for the daily retention scheduler job.""" # Log info: "Scheduled retention job starting..." logger.info("Scheduled retention job starting...") # Assign db = SessionLocal() db = SessionLocal() # Attempt the following; catch errors below try: # Assign summary = apply_retention_policies(db) summary = apply_retention_policies(db) # Log info: "Retention job finished — %s", summary logger.info("Retention job finished — %s", summary) # Handle Exception except Exception: # Log exception: "Retention job failed" logger.exception("Retention job failed") # Roll back all uncommitted changes db.rollback() # Always execute this cleanup block finally: # Close the database session db.close()