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
|
|
@ -10,7 +10,15 @@ 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 JOB_INTERVALS, MAX_INTERVAL, MIN_INTERVAL, apply_interval, scheduler_snapshot
|
||||
from app.scheduler import (
|
||||
JOB_INTERVALS,
|
||||
MAX_INTERVAL,
|
||||
MIN_INTERVAL,
|
||||
apply_interval,
|
||||
scheduler_snapshot,
|
||||
trigger_all,
|
||||
trigger_job,
|
||||
)
|
||||
from app.sync.runner import estimate_deep_backfill
|
||||
|
||||
router = APIRouter(prefix="/api/admin/scheduler", tags=["admin"])
|
||||
|
|
@ -40,6 +48,29 @@ def set_job_interval(
|
|||
return {"id": job_id, "interval_minutes": applied}
|
||||
|
||||
|
||||
@router.post("/jobs/{job_id}/run")
|
||||
def run_job_now(
|
||||
job_id: str,
|
||||
user: User = Depends(admin_user),
|
||||
) -> dict:
|
||||
"""Trigger a job to run immediately (in a background thread), independent of its
|
||||
interval. 409 if it's already running, 404 for an unknown job. On completion the
|
||||
triggering admin gets an inbox notification with the result."""
|
||||
try:
|
||||
result = trigger_job(job_id, actor_id=user.id)
|
||||
except KeyError:
|
||||
raise HTTPException(status_code=404, detail="Unknown job")
|
||||
if result == "already_running":
|
||||
raise HTTPException(status_code=409, detail="Job is already running")
|
||||
return {"id": job_id, "started": True}
|
||||
|
||||
|
||||
@router.post("/run-all")
|
||||
def run_all_now(user: User = Depends(admin_user)) -> dict:
|
||||
"""Trigger every job that isn't already running. Returns the ids actually started."""
|
||||
return {"started": trigger_all(actor_id=user.id)}
|
||||
|
||||
|
||||
@router.get("")
|
||||
def get_scheduler(
|
||||
_: User = Depends(admin_user), db: Session = Depends(get_db)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue