""" Dispute Scheduler for automatic dispute resolution after 24 hours. """ import asyncio from datetime import datetime, timedelta from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload from app.models import Dispute, DisputeStatus, Assignment, AssignmentStatus from app.services.disputes import dispute_service # Configuration CHECK_INTERVAL_SECONDS = 300 # Check every 5 minutes DISPUTE_WINDOW_HOURS = 24 # Disputes auto-resolve after 24 hours class DisputeScheduler: """Background scheduler for automatic dispute resolution.""" def __init__(self): self._running = False self._task: asyncio.Task | None = None async def start(self, session_factory) -> None: """Start the scheduler background task.""" if self._running: return self._running = True self._task = asyncio.create_task(self._run_loop(session_factory)) print("[DisputeScheduler] Started") async def stop(self) -> None: """Stop the scheduler.""" self._running = False if self._task: self._task.cancel() try: await self._task except asyncio.CancelledError: pass print("[DisputeScheduler] Stopped") async def _run_loop(self, session_factory) -> None: """Main scheduler loop.""" while self._running: try: async with session_factory() as db: await self._process_expired_disputes(db) except Exception as e: print(f"[DisputeScheduler] Error in loop: {e}") await asyncio.sleep(CHECK_INTERVAL_SECONDS) async def _process_expired_disputes(self, db: AsyncSession) -> None: """Process and resolve expired disputes.""" cutoff_time = datetime.utcnow() - timedelta(hours=DISPUTE_WINDOW_HOURS) # Find all open disputes that have expired result = await db.execute( select(Dispute) .options( selectinload(Dispute.votes), selectinload(Dispute.assignment).selectinload(Assignment.participant), ) .where( Dispute.status == DisputeStatus.OPEN.value, Dispute.created_at < cutoff_time, ) ) expired_disputes = result.scalars().all() for dispute in expired_disputes: try: result_status, votes_valid, votes_invalid = await dispute_service.resolve_dispute( db, dispute.id ) print( f"[DisputeScheduler] Auto-resolved dispute {dispute.id}: " f"{result_status} (valid: {votes_valid}, invalid: {votes_invalid})" ) except Exception as e: print(f"[DisputeScheduler] Failed to resolve dispute {dispute.id}: {e}") # Global scheduler instance dispute_scheduler = DisputeScheduler()