"""Background scheduler for retrying failed PSA documentation pushes. Runs every 5 minutes via APScheduler, picks up PsaPostLog entries with status='pending_retry' and next_retry_at <= now. """ import logging from datetime import datetime, timezone from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.core.admin_database import _admin_session_factory as async_session_maker from app.models.psa_post_log import PsaPostLog from app.services.psa_documentation_service import retry_failed_push logger = logging.getLogger(__name__) async def process_pending_retries() -> None: """Process all pending PSA push retries that are due.""" async with async_session_maker() as db: try: result = await db.execute( select(PsaPostLog) .where( PsaPostLog.status == "pending_retry", PsaPostLog.next_retry_at <= datetime.now(timezone.utc), PsaPostLog.retry_count < 3, ) .limit(20) # Process in batches ) entries = result.scalars().all() if not entries: return logger.info("Processing %d pending PSA push retries", len(entries)) for entry in entries: success = await retry_failed_push(entry, db) if success: logger.info("PSA retry succeeded for log %s", entry.id) else: logger.warning( "PSA retry %d/%d failed for log %s", entry.retry_count, 3, entry.id, ) await db.commit() except Exception as e: logger.error("PSA retry scheduler error: %s", e) await db.rollback()