"""Celery Beat-triggered housekeeping. Currently just the data-retention purge (DATA_RETENTION_DAYS) - only SourceDocument rows are ever deleted here; see SourceDocumentRepository.delete_older_than for why that's the only safe target in the current FK graph. """ from __future__ import annotations from datetime import UTC, datetime, timedelta from structlog.contextvars import bound_contextvars from app.core.config import get_settings from app.core.logging import get_logger from app.db.session import get_sessionmaker from app.repositories.source_repository import SourceDocumentRepository from app.tasks.base import run_async_task from app.tasks.celery_app import celery_app logger = get_logger(__name__) @celery_app.task(bind=True, name="app.tasks.maintenance.purge_expired_data") def purge_expired_data(self) -> None: with bound_contextvars(task_id=self.request.id): run_async_task(_purge_expired_data_async()) async def _purge_expired_data_async() -> None: settings = get_settings() cutoff = datetime.now(UTC) - timedelta(days=settings.data_retention_days) session_factory = get_sessionmaker() async with session_factory() as db: deleted = await SourceDocumentRepository(db).delete_older_than(cutoff) await db.commit() logger.info( "data_retention_purge_completed", deleted_source_documents=deleted, retention_days=settings.data_retention_days, cutoff=cutoff.isoformat(), )