From eed071dd8f55b7225e3392cce80164cb49e60912 Mon Sep 17 00:00:00 2001 From: Myron Blair Date: Mon, 27 Jul 2026 17:57:50 -0500 Subject: [PATCH] Fix Now Processing panel never showing once the queue backlog exceeds ~500 jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The main queue list sorts by created_at desc and caps at 500 rows, but the FIFO worker processes oldest-first — with a large backlog the actually-running job was routinely outside that window and never reached the frontend at all. Fetch it via a dedicated /transcode/queue/running endpoint instead. --- backend/server.py | 8 ++++++++ frontend/src/pages/TranscodeQueue.jsx | 18 ++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/backend/server.py b/backend/server.py index 6f54ccd..74269d0 100644 --- a/backend/server.py +++ b/backend/server.py @@ -683,6 +683,14 @@ async def list_queue(status: Optional[str] = None, user: dict = Depends(require_ return rows +@api.get("/transcode/queue/running", response_model=Optional[TranscodeJob]) +async def get_running_job(user: dict = Depends(require_admin)): + """The currently-running job, independent of the paginated/sorted list above — with a + large backlog the FIFO worker often processes a job much older than the newest 500 rows, + which would otherwise never surface in the main list's created_at-desc window.""" + return await db.transcode_queue.find_one({"status": "running"}, {"_id": 0}) + + @api.get("/transcode/queue/stats") async def queue_stats(user: dict = Depends(require_admin)): pipeline = [{"$group": {"_id": "$status", "n": {"$sum": 1}}}] diff --git a/frontend/src/pages/TranscodeQueue.jsx b/frontend/src/pages/TranscodeQueue.jsx index efb9357..9636fb7 100644 --- a/frontend/src/pages/TranscodeQueue.jsx +++ b/frontend/src/pages/TranscodeQueue.jsx @@ -15,6 +15,7 @@ const STATUS_COLORS = { export default function TranscodeQueue() { const [jobs, setJobs] = useState([]); const [stats, setStats] = useState({ pending: 0, running: 0, done: 0, failed: 0, cancelled: 0, paused: false, auto_transcode: "off" }); + const [runningJob, setRunningJob] = useState(null); const [loading, setLoading] = useState(false); const load = async () => { @@ -25,19 +26,24 @@ export default function TranscodeQueue() { setStats(s.data); } finally { setLoading(false); } }; - useEffect(() => { load(); }, []); + // The running job can be far outside the main list's created_at-desc/500-row window once + // there's a large backlog (the FIFO worker processes oldest-first), so it's fetched separately + // rather than derived from `jobs`. + const loadRunning = async () => { + try { const { data } = await api.get("/transcode/queue/running"); setRunningJob(data); } + catch { /* ignore transient poll failures */ } + }; + useEffect(() => { load(); loadRunning(); }, []); // Poll while jobs are active — faster while something is actually running so the // progress bar feels live, slower while only pending jobs are waiting. useEffect(() => { - const running = jobs.some((j) => j.status === "running"); const pending = jobs.some((j) => j.status === "pending"); - if (!running && !pending) return; - const t = setInterval(load, running ? 2000 : 4000); + if (!runningJob && !pending) return; + const t = setInterval(() => { load(); loadRunning(); }, runningJob ? 2000 : 4000); return () => clearInterval(t); - }, [jobs]); + }, [jobs, runningJob]); - const runningJob = jobs.find((j) => j.status === "running"); const listedJobs = jobs.filter((j) => j.status !== "running"); const cancel = async (id) => {