"""Daily APScheduler cron that purges expired trash. A single job at 03:30 UTC (services/scheduler.py). Iterates every user and applies that user's own `trash_retention_days` setting; 0 disables auto-purge for that user. """ from __future__ import annotations import asyncio import logging from apscheduler.triggers.cron import CronTrigger from sqlalchemy import select from scribe.models import async_session from scribe.models.user import User from scribe.services import trash as trash_svc from scribe.services.scheduler import ScheduledJob from scribe.services.settings import get_setting logger = logging.getLogger(__name__) async def _run_purge() -> None: async with async_session() as session: user_ids = (await session.execute(select(User.id))).scalars().all() purged = 0 for uid in user_ids: raw = await get_setting(uid, "trash_retention_days", "90") try: days = int(raw) except (TypeError, ValueError): days = 90 purged += await trash_svc.purge_expired(uid, days) if purged: logger.info("trash purge: removed %d expired row(s)", purged) else: logger.debug("trash purge: nothing expired") _JOB = ScheduledJob("trash_retention_purge", _run_purge, label="Trash retention") def start_trash_scheduler(loop: asyncio.AbstractEventLoop) -> None: _JOB.start(loop, CronTrigger(hour=3, minute=30, timezone="UTC"), describe="daily 03:30 UTC") def stop_trash_scheduler() -> None: _JOB.stop()