feat(scheduler): admin run-now/run-all triggers + live progress + completion notices
Add per-job "Run now" buttons and a "Start all now" button to the admin Scheduler dashboard (admin-gated endpoints). Triggers run the job in a background thread independent of its interval, refusing a concurrent run (409). While running, the long jobs (maintenance, enrich, backfill, shorts) report live progress through a decoupled contextvar sink, shown as a progress bar on the job row via the existing 4s poll. A manually-triggered run posts a completion notification to the triggering admin's inbox (scheduled runs stay silent to avoid spam); the inbox renders the "scheduler" type trilingually from type+data. While here, give the maintenance job its missing dashboard label/description in all three languages.
This commit is contained in:
parent
3a0789ebe7
commit
ed4194a8d3
15 changed files with 344 additions and 30 deletions
|
|
@ -25,7 +25,7 @@ from datetime import datetime, timedelta, timezone
|
|||
from sqlalchemy import or_, select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app import quota
|
||||
from app import progress, quota
|
||||
from app.config import settings
|
||||
from app.models import Playlist, PlaylistItem, Video, VideoState
|
||||
from app.notifications import create_notification
|
||||
|
|
@ -147,6 +147,7 @@ def _recheck_flagged(db: Session, yt: YouTubeClient) -> dict:
|
|||
)
|
||||
if not flagged:
|
||||
return {"checked": 0, "recovered": 0, "deleted": 0, "notified": 0}
|
||||
progress.report(0, len(flagged), "recheck")
|
||||
items = {it["id"]: it for it in yt.get_videos([v.id for v in flagged])}
|
||||
now = _now()
|
||||
recovered = 0
|
||||
|
|
@ -221,6 +222,7 @@ def _revalidate_rolling(db: Session, yt: YouTubeClient) -> dict:
|
|||
flagged_new += 1
|
||||
db.commit()
|
||||
checked += len(page)
|
||||
progress.report(checked, batch, "revalidate")
|
||||
return {"checked": checked, "flagged": flagged_new}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import logging
|
|||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app import quota
|
||||
from app import progress, quota
|
||||
from app.config import settings
|
||||
|
||||
log = logging.getLogger("subfeed.sync")
|
||||
|
|
@ -64,6 +64,7 @@ def run_enrich(db: Session, max_batches: int = 200, floor: int = 200) -> int:
|
|||
break
|
||||
n = enrich_pending(db, yt)
|
||||
total += n
|
||||
progress.report(total, None, "enrich") # total unknown (drains until empty)
|
||||
if n == 0:
|
||||
break
|
||||
# Revisit transient live/upcoming videos (enrich_pending is one-shot) so an ended
|
||||
|
|
@ -121,6 +122,7 @@ def run_recent_backfill(
|
|||
try:
|
||||
videos_added += backfill_channel_recent(db, yt, channel)
|
||||
processed += 1
|
||||
progress.report(processed, len(channels), "backfill_recent")
|
||||
except Exception:
|
||||
db.rollback()
|
||||
log.exception("Recent backfill failed for channel %s", channel.id)
|
||||
|
|
@ -166,6 +168,7 @@ def run_deep_backfill(db: Session, max_channels: int = 10, max_pages: int = 5) -
|
|||
try:
|
||||
videos_added += backfill_channel_deep(db, yt, channel, max_pages)
|
||||
processed += 1
|
||||
progress.report(processed, len(channels), "backfill_deep")
|
||||
except Exception:
|
||||
db.rollback()
|
||||
log.exception("Deep backfill failed for channel %s", channel.id)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from sqlalchemy import and_, func, or_, select, update
|
|||
from sqlalchemy.dialects.postgresql import insert as pg_insert
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app import progress
|
||||
from app.config import settings
|
||||
from app.models import Channel, Video
|
||||
from app.youtube.client import YouTubeClient, best_thumbnail
|
||||
|
|
@ -365,5 +366,6 @@ def run_shorts_classification(db: Session, limit: int | None = None) -> dict:
|
|||
probed += 1
|
||||
if result:
|
||||
shorts += 1
|
||||
progress.report(probed, len(candidates), "probe")
|
||||
db.commit()
|
||||
return {"probed": probed, "shorts": shorts}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue