"""Admin Scheduler dashboard: a live view of what the background scheduler is doing — per-job run activity (from the in-process scheduler), the work still queued (DB-derived), and the shared quota picture.""" from fastapi import APIRouter, Depends from sqlalchemy import and_, func, or_, select from sqlalchemy.orm import Session from app import quota, state from app.config import settings from app.db import get_db from app.models import Channel, Subscription, User, Video from app.routes.admin import admin_user from app.scheduler import scheduler_snapshot from app.sync.runner import estimate_deep_backfill router = APIRouter(prefix="/api/admin/scheduler", tags=["admin"]) @router.get("") def get_scheduler( _: User = Depends(admin_user), db: Session = Depends(get_db) ) -> dict: snap = scheduler_snapshot() # Work still queued (shared catalog, so these are instance-wide, not per-user). deep_requested = ( select(Subscription.id) .where( Subscription.channel_id == Channel.id, Subscription.deep_requested.is_(True), ) .exists() ) deep_channels = ( db.execute( select(Channel).where(Channel.backfill_done.is_(False), deep_requested) ) .scalars() .all() ) deep_eta = estimate_deep_backfill(db, deep_channels) queue = { "channels_recent_pending": db.scalar( select(func.count()).select_from(Channel).where(Channel.recent_synced_at.is_(None)) ) or 0, "channels_deep_pending": deep_eta["channels_pending"], "deep_eta_seconds": deep_eta["eta_seconds"], "videos_pending_enrich": db.scalar( select(func.count()).select_from(Video).where(Video.enriched_at.is_(None)) ) or 0, "videos_pending_shorts": db.scalar( select(func.count()) .select_from(Video) .where(Video.shorts_probed.is_(False), Video.enriched_at.is_not(None)) ) or 0, "videos_live_refresh": db.scalar( select(func.count()) .select_from(Video) .where( or_( Video.live_status.in_(("live", "upcoming")), and_(Video.live_status == "was_live", Video.duration_seconds.is_(None)), ) ) ) or 0, } used = quota.units_used_today(db) quota_info = { "used_today": used, "remaining_today": quota.remaining_today(db), "daily_budget": settings.quota_daily_budget, "backfill_reserve": settings.backfill_quota_reserve, } return { **snap, "paused": state.is_sync_paused(db), "queue": queue, "quota": quota_info, }