7458 lines
335 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="Build Power. Not Rent It. Own your digital infrastructure.">
<meta name="author" content="Bunker Operations">
<link rel="canonical" href="https://bnkserve.org/v2/features/media/jobs/">
<link rel="prev" href="../public-gallery/">
<link rel="next" href="../../newsletter/">
<link rel="icon" href="../../../../assets/favicon.png">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.7.1">
<title>Jobs - Changemaker Lite</title>
<link rel="stylesheet" href="../../../../assets/stylesheets/main.484c7ddc.min.css">
<link rel="stylesheet" href="../../../../assets/stylesheets/palette.ab4e12ef.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Inter";--md-code-font:"JetBrains Mono"}</style>
<link rel="stylesheet" href="../../../../stylesheets/extra.css">
<link rel="stylesheet" href="../../../../stylesheets/home.css">
<link rel="stylesheet" href="../../../../assets/css/video-player.css">
<script>__md_scope=new URL("../../../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
<meta property="og:type" content="website" />
<meta property="og:title" content="Jobs - Changemaker Lite" />
<meta property="og:description" content="Build Power. Not Rent It. Own your digital infrastructure." />
<meta property="og:image" content="https://bnkserve.org/assets/images/social/v2/features/media/jobs.png" />
<meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:url" content="https://bnkserve.org/v2/features/media/jobs/" />
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:title" content="Jobs - Changemaker Lite" />
<meta property="twitter:description" content="Build Power. Not Rent It. Own your digital infrastructure." />
<meta property="twitter:image" content="https://bnkserve.org/assets/images/social/v2/features/media/jobs.png" />
</head>
<body dir="ltr" data-md-color-scheme="slate" data-md-color-primary="deep-purple" data-md-color-accent="amber">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#media-job-queue-system" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header md-header--shadow md-header--lifted" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href="../../../.." title="Changemaker Lite" class="md-header__button md-logo" aria-label="Changemaker Lite" data-md-component="logo">
<img src="../../../../assets/logo.png" alt="logo">
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Changemaker Lite
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Jobs
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="" data-md-color-scheme="slate" data-md-color-primary="deep-purple" data-md-color-accent="amber" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_0">
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_1" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m17.75 4.09-2.53 1.94.91 3.06-2.63-1.81-2.63 1.81.91-3.06-2.53-1.94L12.44 4l1.06-3 1.06 3zm3.5 6.91-1.64 1.25.59 1.98-1.7-1.17-1.7 1.17.59-1.98L15.75 11l2.06-.05L18.5 9l.69 1.95zm-2.28 4.95c.83-.08 1.72 1.1 1.19 1.85-.32.45-.66.87-1.08 1.27C15.17 23 8.84 23 4.94 19.07c-3.91-3.9-3.91-10.24 0-14.14.4-.4.82-.76 1.27-1.08.75-.53 1.93.36 1.85 1.19-.27 2.86.69 5.83 2.89 8.02a9.96 9.96 0 0 0 8.02 2.89m-1.64 2.02a12.08 12.08 0 0 1-7.8-3.47c-2.17-2.19-3.33-5-3.49-7.82-2.81 3.14-2.7 7.96.31 10.98 3.02 3.01 7.84 3.12 10.98.31"/></svg>
</label>
<input class="md-option" data-md-color-media="" data-md-color-scheme="default" data-md-color-primary="deep-purple" data-md-color-accent="amber" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_1">
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_0" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 7a5 5 0 0 1 5 5 5 5 0 0 1-5 5 5 5 0 0 1-5-5 5 5 0 0 1 5-5m0 2a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3m0-7 2.39 3.42C13.65 5.15 12.84 5 12 5s-1.65.15-2.39.42zM3.34 7l4.16-.35A7.2 7.2 0 0 0 5.94 8.5c-.44.74-.69 1.5-.83 2.29zm.02 10 1.76-3.77a7.131 7.131 0 0 0 2.38 4.14zM20.65 7l-1.77 3.79a7.02 7.02 0 0 0-2.38-4.15zm-.01 10-4.14.36c.59-.51 1.12-1.14 1.54-1.86.42-.73.69-1.5.83-2.29zM12 22l-2.41-3.44c.74.27 1.55.44 2.41.44.82 0 1.63-.17 2.37-.44z"/></svg>
</label>
</form>
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<a href="javascript:void(0)" class="md-search__icon md-icon" title="Share" aria-label="Share" data-clipboard data-clipboard-text="" data-md-component="search-share" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66 0 1.61 1.31 2.91 2.92 2.91s2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08"/></svg>
</a>
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
</button>
</nav>
<div class="md-search__suggest" data-md-component="search-suggest"></div>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
<div class="md-header__source">
<a href="https://gitea.bnkops.com/admin/changemaker.lite" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
</div>
<div class="md-source__repository">
changemaker.lite
</div>
</a>
</div>
</nav>
<nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
<div class="md-grid">
<ul class="md-tabs__list">
<li class="md-tabs__item">
<a href="../../../.." class="md-tabs__link">
Home
</a>
</li>
<li class="md-tabs__item md-tabs__item--active">
<a href="../../../" class="md-tabs__link">
V2 Documentation
</a>
</li>
<li class="md-tabs__item">
<a href="../../../../phil/" class="md-tabs__link">
Philosophy
</a>
</li>
<li class="md-tabs__item">
<a href="../../../../v1/" class="md-tabs__link">
V1 Documentation (Legacy)
</a>
</li>
<li class="md-tabs__item">
<a href="../../../../blog/" class="md-tabs__link">
Blog
</a>
</li>
</ul>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary md-nav--lifted" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="../../../.." title="Changemaker Lite" class="md-nav__button md-logo" aria-label="Changemaker Lite" data-md-component="logo">
<img src="../../../../assets/logo.png" alt="logo">
</a>
Changemaker Lite
</label>
<div class="md-nav__source">
<a href="https://gitea.bnkops.com/admin/changemaker.lite" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
</div>
<div class="md-source__repository">
changemaker.lite
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../.." class="md-nav__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2" checked>
<div class="md-nav__link md-nav__container">
<a href="../../../" class="md-nav__link ">
<span class="md-ellipsis">
V2 Documentation
</span>
</a>
<label class="md-nav__link " for="__nav_2" id="__nav_2_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_2_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_2">
<span class="md-nav__icon md-icon"></span>
V2 Documentation
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_2" >
<div class="md-nav__link md-nav__container">
<a href="../../../getting-started/" class="md-nav__link ">
<span class="md-ellipsis">
Getting Started
</span>
</a>
<label class="md-nav__link " for="__nav_2_2" id="__nav_2_2_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_2">
<span class="md-nav__icon md-icon"></span>
Getting Started
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../getting-started/quick-start/" class="md-nav__link">
<span class="md-ellipsis">
Quick Start
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_3" >
<div class="md-nav__link md-nav__container">
<a href="../../../architecture/" class="md-nav__link ">
<span class="md-ellipsis">
Architecture
</span>
</a>
<label class="md-nav__link " for="__nav_2_3" id="__nav_2_3_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_3">
<span class="md-nav__icon md-icon"></span>
Architecture
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../architecture/dual-api/" class="md-nav__link">
<span class="md-ellipsis">
Dual API System
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../architecture/authentication/" class="md-nav__link">
<span class="md-ellipsis">
Authentication & Security
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_4" >
<div class="md-nav__link md-nav__container">
<a href="../../../backend/" class="md-nav__link ">
<span class="md-ellipsis">
Backend
</span>
</a>
<label class="md-nav__link " for="__nav_2_4" id="__nav_2_4_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_4">
<span class="md-nav__icon md-icon"></span>
Backend
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../../backend/modules/" class="md-nav__link">
<span class="md-ellipsis">
Modules
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../../backend/services/" class="md-nav__link">
<span class="md-ellipsis">
Services
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../../backend/middleware/" class="md-nav__link">
<span class="md-ellipsis">
Middleware
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../../backend/utilities/" class="md-nav__link">
<span class="md-ellipsis">
Utilities
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_5" >
<div class="md-nav__link md-nav__container">
<a href="../../../frontend/" class="md-nav__link ">
<span class="md-ellipsis">
Frontend
</span>
</a>
<label class="md-nav__link " for="__nav_2_5" id="__nav_2_5_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_5">
<span class="md-nav__icon md-icon"></span>
Frontend
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../../frontend/components/" class="md-nav__link">
<span class="md-ellipsis">
Components
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../../frontend/layouts/" class="md-nav__link">
<span class="md-ellipsis">
Layouts
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../../frontend/pages/" class="md-nav__link">
<span class="md-ellipsis">
Pages
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_6" >
<div class="md-nav__link md-nav__container">
<a href="../../../database/" class="md-nav__link ">
<span class="md-ellipsis">
Database
</span>
</a>
<label class="md-nav__link " for="__nav_2_6" id="__nav_2_6_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_6_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_6">
<span class="md-nav__icon md-icon"></span>
Database
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../database/schema/" class="md-nav__link">
<span class="md-ellipsis">
Schema Overview
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../database/migrations/" class="md-nav__link">
<span class="md-ellipsis">
Migrations
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../database/seeding/" class="md-nav__link">
<span class="md-ellipsis">
Seeding
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../database/indexes/" class="md-nav__link">
<span class="md-ellipsis">
Indexes
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../../database/models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_7" checked>
<div class="md-nav__link md-nav__container">
<a href="../../" class="md-nav__link ">
<span class="md-ellipsis">
Features
</span>
</a>
<label class="md-nav__link " for="__nav_2_7" id="__nav_2_7_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_7_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_2_7">
<span class="md-nav__icon md-icon"></span>
Features
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../influence/" class="md-nav__link">
<span class="md-ellipsis">
Influence
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../map/" class="md-nav__link">
<span class="md-ellipsis">
Map
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../landing-pages/" class="md-nav__link">
<span class="md-ellipsis">
Landing Pages
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../email-templates/" class="md-nav__link">
<span class="md-ellipsis">
Email Templates
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_7_6" checked>
<div class="md-nav__link md-nav__container">
<a href="../" class="md-nav__link ">
<span class="md-ellipsis">
Media
</span>
</a>
<label class="md-nav__link " for="__nav_2_7_6" id="__nav_2_7_6_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_7_6_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_2_7_6">
<span class="md-nav__icon md-icon"></span>
Media
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../video-library/" class="md-nav__link">
<span class="md-ellipsis">
Video Library
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../upload/" class="md-nav__link">
<span class="md-ellipsis">
Upload System
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../public-gallery/" class="md-nav__link">
<span class="md-ellipsis">
Public Gallery
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
<span class="md-ellipsis">
Jobs
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Jobs
</span>
</a>
<nav class="md-nav md-nav--secondary" aria-label="On this page">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
On this page
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#overview" class="md-nav__link">
<span class="md-ellipsis">
Overview
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#architecture" class="md-nav__link">
<span class="md-ellipsis">
Architecture
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#database-model" class="md-nav__link">
<span class="md-ellipsis">
Database Model
</span>
</a>
<nav class="md-nav" aria-label="Database Model">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#jobs-table-schema" class="md-nav__link">
<span class="md-ellipsis">
Jobs Table Schema
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#job-types-enum" class="md-nav__link">
<span class="md-ellipsis">
Job Types Enum
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#job-status-enum" class="md-nav__link">
<span class="md-ellipsis">
Job Status Enum
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#resource-categories" class="md-nav__link">
<span class="md-ellipsis">
Resource Categories
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#api-endpoints" class="md-nav__link">
<span class="md-ellipsis">
API Endpoints
</span>
</a>
<nav class="md-nav" aria-label="API Endpoints">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#list-jobs" class="md-nav__link">
<span class="md-ellipsis">
List Jobs
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#get-job-details" class="md-nav__link">
<span class="md-ellipsis">
Get Job Details
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#create-job" class="md-nav__link">
<span class="md-ellipsis">
Create Job
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#retry-failed-job" class="md-nav__link">
<span class="md-ellipsis">
Retry Failed Job
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#cancel-job" class="md-nav__link">
<span class="md-ellipsis">
Cancel Job
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#pauseresume-job" class="md-nav__link">
<span class="md-ellipsis">
Pause/Resume Job
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#queue-statistics" class="md-nav__link">
<span class="md-ellipsis">
Queue Statistics
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#admin-workflow" class="md-nav__link">
<span class="md-ellipsis">
Admin Workflow
</span>
</a>
<nav class="md-nav" aria-label="Admin Workflow">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#viewing-job-queue" class="md-nav__link">
<span class="md-ellipsis">
Viewing Job Queue
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#creating-jobs-manually" class="md-nav__link">
<span class="md-ellipsis">
Creating Jobs Manually
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#monitoring-job-progress" class="md-nav__link">
<span class="md-ellipsis">
Monitoring Job Progress
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#retrying-failed-jobs" class="md-nav__link">
<span class="md-ellipsis">
Retrying Failed Jobs
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#cancelling-jobs" class="md-nav__link">
<span class="md-ellipsis">
Cancelling Jobs
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#pausingresuming-jobs" class="md-nav__link">
<span class="md-ellipsis">
Pausing/Resuming Jobs
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#job-type-details" class="md-nav__link">
<span class="md-ellipsis">
Job Type Details
</span>
</a>
<nav class="md-nav" aria-label="Job Type Details">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#scan-jobs-scan-public_scan" class="md-nav__link">
<span class="md-ellipsis">
Scan Jobs (scan, public_scan)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#validation-jobs-validate" class="md-nav__link">
<span class="md-ellipsis">
Validation Jobs (validate)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#re-encode-jobs-reencode_streaming" class="md-nav__link">
<span class="md-ellipsis">
Re-encode Jobs (reencode_streaming)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#compilation-jobs-compile_random-compile_quad-compile_mega" class="md-nav__link">
<span class="md-ellipsis">
Compilation Jobs (compile_random, compile_quad, compile_mega)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#digest-generation-digest_generate" class="md-nav__link">
<span class="md-ellipsis">
Digest Generation (digest_generate)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#thumbnail-generation-thumbnail_generate" class="md-nav__link">
<span class="md-ellipsis">
Thumbnail Generation (thumbnail_generate)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#code-examples" class="md-nav__link">
<span class="md-ellipsis">
Code Examples
</span>
</a>
<nav class="md-nav" aria-label="Code Examples">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#create-re-encode-job" class="md-nav__link">
<span class="md-ellipsis">
Create Re-encode Job
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#job-worker-polling-loop" class="md-nav__link">
<span class="md-ellipsis">
Job Worker (Polling Loop)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#frontend-jobs-page" class="md-nav__link">
<span class="md-ellipsis">
Frontend: Jobs Page
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#troubleshooting" class="md-nav__link">
<span class="md-ellipsis">
Troubleshooting
</span>
</a>
<nav class="md-nav" aria-label="Troubleshooting">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#problem-jobs-stuck-in-pending" class="md-nav__link">
<span class="md-ellipsis">
Problem: Jobs Stuck in Pending
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#problem-job-fails-immediately" class="md-nav__link">
<span class="md-ellipsis">
Problem: Job Fails Immediately
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#problem-re-encode-job-hangs-at-same-progress" class="md-nav__link">
<span class="md-ellipsis">
Problem: Re-encode Job Hangs at Same Progress
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#problem-gpu-out-of-memory-errors" class="md-nav__link">
<span class="md-ellipsis">
Problem: GPU Out of Memory Errors
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#performance-considerations" class="md-nav__link">
<span class="md-ellipsis">
Performance Considerations
</span>
</a>
<nav class="md-nav" aria-label="Performance Considerations">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#job-queue-throughput" class="md-nav__link">
<span class="md-ellipsis">
Job Queue Throughput
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#database-performance" class="md-nav__link">
<span class="md-ellipsis">
Database Performance
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#monitoring-observability" class="md-nav__link">
<span class="md-ellipsis">
Monitoring &amp; Observability
</span>
</a>
<nav class="md-nav" aria-label="Monitoring &amp; Observability">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#prometheus-metrics" class="md-nav__link">
<span class="md-ellipsis">
Prometheus Metrics
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#grafana-dashboard-panel" class="md-nav__link">
<span class="md-ellipsis">
Grafana Dashboard Panel
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#related-documentation" class="md-nav__link">
<span class="md-ellipsis">
Related Documentation
</span>
</a>
<nav class="md-nav" aria-label="Related Documentation">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#backend-documentation" class="md-nav__link">
<span class="md-ellipsis">
Backend Documentation
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#frontend-documentation" class="md-nav__link">
<span class="md-ellipsis">
Frontend Documentation
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#feature-documentation" class="md-nav__link">
<span class="md-ellipsis">
Feature Documentation
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#next-steps" class="md-nav__link">
<span class="md-ellipsis">
Next Steps
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../newsletter/" class="md-nav__link">
<span class="md-ellipsis">
Newsletter
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../observability/" class="md-nav__link">
<span class="md-ellipsis">
Observability
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../tunnel/" class="md-nav__link">
<span class="md-ellipsis">
Tunnel
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_8" >
<div class="md-nav__link md-nav__container">
<a href="../../../deployment/" class="md-nav__link ">
<span class="md-ellipsis">
Deployment
</span>
</a>
<label class="md-nav__link " for="__nav_2_8" id="__nav_2_8_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_8_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_8">
<span class="md-nav__icon md-icon"></span>
Deployment
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../deployment/docker-compose/" class="md-nav__link">
<span class="md-ellipsis">
Docker Compose
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../deployment/environment-variables/" class="md-nav__link">
<span class="md-ellipsis">
Environment Variables
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../deployment/nginx/" class="md-nav__link">
<span class="md-ellipsis">
Nginx Configuration
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../deployment/ssl-tls/" class="md-nav__link">
<span class="md-ellipsis">
SSL/TLS
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../deployment/tunneling/" class="md-nav__link">
<span class="md-ellipsis">
Tunneling
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../deployment/monitoring-stack/" class="md-nav__link">
<span class="md-ellipsis">
Monitoring Stack
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../deployment/healthchecks/" class="md-nav__link">
<span class="md-ellipsis">
Health Checks
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../deployment/scaling/" class="md-nav__link">
<span class="md-ellipsis">
Scaling
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../deployment/backup-restore/" class="md-nav__link">
<span class="md-ellipsis">
Backup & Restore
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_9" >
<div class="md-nav__link md-nav__container">
<a href="../../../development/" class="md-nav__link ">
<span class="md-ellipsis">
Development
</span>
</a>
<label class="md-nav__link " for="__nav_2_9" id="__nav_2_9_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_9_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_9">
<span class="md-nav__icon md-icon"></span>
Development
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../development/local-setup/" class="md-nav__link">
<span class="md-ellipsis">
Local Setup
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../development/docker-workflow/" class="md-nav__link">
<span class="md-ellipsis">
Docker Workflow
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../development/git-workflow/" class="md-nav__link">
<span class="md-ellipsis">
Git Workflow
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../development/npm-commands/" class="md-nav__link">
<span class="md-ellipsis">
NPM Commands
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../development/migrations/" class="md-nav__link">
<span class="md-ellipsis">
Migrations
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../development/typescript/" class="md-nav__link">
<span class="md-ellipsis">
TypeScript
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../development/testing/" class="md-nav__link">
<span class="md-ellipsis">
Testing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../development/debugging/" class="md-nav__link">
<span class="md-ellipsis">
Debugging
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../development/code-style/" class="md-nav__link">
<span class="md-ellipsis">
Code Style
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_10" >
<div class="md-nav__link md-nav__container">
<a href="../../../api-reference/" class="md-nav__link ">
<span class="md-ellipsis">
API Reference
</span>
</a>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_10_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_10">
<span class="md-nav__icon md-icon"></span>
API Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_11" >
<div class="md-nav__link md-nav__container">
<a href="../../../user-guides/" class="md-nav__link ">
<span class="md-ellipsis">
User Guides
</span>
</a>
<label class="md-nav__link " for="__nav_2_11" id="__nav_2_11_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_11_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_11">
<span class="md-nav__icon md-icon"></span>
User Guides
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../user-guides/admin-guide/" class="md-nav__link">
<span class="md-ellipsis">
Admin Guide
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../user-guides/campaign-manager-guide/" class="md-nav__link">
<span class="md-ellipsis">
Campaign Manager Guide
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../user-guides/map-organizer-guide/" class="md-nav__link">
<span class="md-ellipsis">
Map Organizer Guide
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../user-guides/content-editor-guide/" class="md-nav__link">
<span class="md-ellipsis">
Content Editor Guide
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../user-guides/volunteer-guide/" class="md-nav__link">
<span class="md-ellipsis">
Volunteer Guide
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_12" >
<div class="md-nav__link md-nav__container">
<a href="../../../troubleshooting/" class="md-nav__link ">
<span class="md-ellipsis">
Troubleshooting
</span>
</a>
<label class="md-nav__link " for="__nav_2_12" id="__nav_2_12_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_12_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_12">
<span class="md-nav__icon md-icon"></span>
Troubleshooting
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../troubleshooting/faq/" class="md-nav__link">
<span class="md-ellipsis">
FAQ
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../troubleshooting/common-errors/" class="md-nav__link">
<span class="md-ellipsis">
Common Errors
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../troubleshooting/auth-issues/" class="md-nav__link">
<span class="md-ellipsis">
Auth Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../troubleshooting/database-issues/" class="md-nav__link">
<span class="md-ellipsis">
Database Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../troubleshooting/docker-issues/" class="md-nav__link">
<span class="md-ellipsis">
Docker Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../troubleshooting/email-issues/" class="md-nav__link">
<span class="md-ellipsis">
Email Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../troubleshooting/geocoding-issues/" class="md-nav__link">
<span class="md-ellipsis">
Geocoding Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../troubleshooting/monitoring-issues/" class="md-nav__link">
<span class="md-ellipsis">
Monitoring Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../troubleshooting/performance-optimization/" class="md-nav__link">
<span class="md-ellipsis">
Performance Optimization
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_13" >
<div class="md-nav__link md-nav__container">
<a href="../../../migration/" class="md-nav__link ">
<span class="md-ellipsis">
Migration
</span>
</a>
<label class="md-nav__link " for="__nav_2_13" id="__nav_2_13_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_13_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_13">
<span class="md-nav__icon md-icon"></span>
Migration
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../migration/feature-parity/" class="md-nav__link">
<span class="md-ellipsis">
Feature Parity
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../migration/breaking-changes/" class="md-nav__link">
<span class="md-ellipsis">
Breaking Changes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../migration/api-changes/" class="md-nav__link">
<span class="md-ellipsis">
API Changes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../migration/data-migration/" class="md-nav__link">
<span class="md-ellipsis">
Data Migration
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2_14" >
<div class="md-nav__link md-nav__container">
<a href="../../../contributing/" class="md-nav__link ">
<span class="md-ellipsis">
Contributing
</span>
</a>
<label class="md-nav__link " for="__nav_2_14" id="__nav_2_14_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_14_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2_14">
<span class="md-nav__icon md-icon"></span>
Contributing
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../contributing/development-setup/" class="md-nav__link">
<span class="md-ellipsis">
Development Setup
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../contributing/code-of-conduct/" class="md-nav__link">
<span class="md-ellipsis">
Code of Conduct
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../contributing/pull-requests/" class="md-nav__link">
<span class="md-ellipsis">
Pull Requests
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../contributing/roadmap/" class="md-nav__link">
<span class="md-ellipsis">
Roadmap
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../../../phil/" class="md-nav__link">
<span class="md-ellipsis">
Philosophy
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../../../v1/" class="md-nav__link">
<span class="md-ellipsis">
V1 Documentation (Legacy)
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
<li class="md-nav__item md-nav__item--pruned md-nav__item--nested">
<a href="../../../../blog/" class="md-nav__link">
<span class="md-ellipsis">
Blog
</span>
<span class="md-nav__icon md-icon"></span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="On this page">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
On this page
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#overview" class="md-nav__link">
<span class="md-ellipsis">
Overview
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#architecture" class="md-nav__link">
<span class="md-ellipsis">
Architecture
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#database-model" class="md-nav__link">
<span class="md-ellipsis">
Database Model
</span>
</a>
<nav class="md-nav" aria-label="Database Model">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#jobs-table-schema" class="md-nav__link">
<span class="md-ellipsis">
Jobs Table Schema
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#job-types-enum" class="md-nav__link">
<span class="md-ellipsis">
Job Types Enum
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#job-status-enum" class="md-nav__link">
<span class="md-ellipsis">
Job Status Enum
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#resource-categories" class="md-nav__link">
<span class="md-ellipsis">
Resource Categories
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#api-endpoints" class="md-nav__link">
<span class="md-ellipsis">
API Endpoints
</span>
</a>
<nav class="md-nav" aria-label="API Endpoints">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#list-jobs" class="md-nav__link">
<span class="md-ellipsis">
List Jobs
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#get-job-details" class="md-nav__link">
<span class="md-ellipsis">
Get Job Details
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#create-job" class="md-nav__link">
<span class="md-ellipsis">
Create Job
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#retry-failed-job" class="md-nav__link">
<span class="md-ellipsis">
Retry Failed Job
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#cancel-job" class="md-nav__link">
<span class="md-ellipsis">
Cancel Job
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#pauseresume-job" class="md-nav__link">
<span class="md-ellipsis">
Pause/Resume Job
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#queue-statistics" class="md-nav__link">
<span class="md-ellipsis">
Queue Statistics
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#admin-workflow" class="md-nav__link">
<span class="md-ellipsis">
Admin Workflow
</span>
</a>
<nav class="md-nav" aria-label="Admin Workflow">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#viewing-job-queue" class="md-nav__link">
<span class="md-ellipsis">
Viewing Job Queue
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#creating-jobs-manually" class="md-nav__link">
<span class="md-ellipsis">
Creating Jobs Manually
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#monitoring-job-progress" class="md-nav__link">
<span class="md-ellipsis">
Monitoring Job Progress
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#retrying-failed-jobs" class="md-nav__link">
<span class="md-ellipsis">
Retrying Failed Jobs
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#cancelling-jobs" class="md-nav__link">
<span class="md-ellipsis">
Cancelling Jobs
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#pausingresuming-jobs" class="md-nav__link">
<span class="md-ellipsis">
Pausing/Resuming Jobs
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#job-type-details" class="md-nav__link">
<span class="md-ellipsis">
Job Type Details
</span>
</a>
<nav class="md-nav" aria-label="Job Type Details">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#scan-jobs-scan-public_scan" class="md-nav__link">
<span class="md-ellipsis">
Scan Jobs (scan, public_scan)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#validation-jobs-validate" class="md-nav__link">
<span class="md-ellipsis">
Validation Jobs (validate)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#re-encode-jobs-reencode_streaming" class="md-nav__link">
<span class="md-ellipsis">
Re-encode Jobs (reencode_streaming)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#compilation-jobs-compile_random-compile_quad-compile_mega" class="md-nav__link">
<span class="md-ellipsis">
Compilation Jobs (compile_random, compile_quad, compile_mega)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#digest-generation-digest_generate" class="md-nav__link">
<span class="md-ellipsis">
Digest Generation (digest_generate)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#thumbnail-generation-thumbnail_generate" class="md-nav__link">
<span class="md-ellipsis">
Thumbnail Generation (thumbnail_generate)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#code-examples" class="md-nav__link">
<span class="md-ellipsis">
Code Examples
</span>
</a>
<nav class="md-nav" aria-label="Code Examples">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#create-re-encode-job" class="md-nav__link">
<span class="md-ellipsis">
Create Re-encode Job
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#job-worker-polling-loop" class="md-nav__link">
<span class="md-ellipsis">
Job Worker (Polling Loop)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#frontend-jobs-page" class="md-nav__link">
<span class="md-ellipsis">
Frontend: Jobs Page
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#troubleshooting" class="md-nav__link">
<span class="md-ellipsis">
Troubleshooting
</span>
</a>
<nav class="md-nav" aria-label="Troubleshooting">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#problem-jobs-stuck-in-pending" class="md-nav__link">
<span class="md-ellipsis">
Problem: Jobs Stuck in Pending
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#problem-job-fails-immediately" class="md-nav__link">
<span class="md-ellipsis">
Problem: Job Fails Immediately
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#problem-re-encode-job-hangs-at-same-progress" class="md-nav__link">
<span class="md-ellipsis">
Problem: Re-encode Job Hangs at Same Progress
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#problem-gpu-out-of-memory-errors" class="md-nav__link">
<span class="md-ellipsis">
Problem: GPU Out of Memory Errors
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#performance-considerations" class="md-nav__link">
<span class="md-ellipsis">
Performance Considerations
</span>
</a>
<nav class="md-nav" aria-label="Performance Considerations">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#job-queue-throughput" class="md-nav__link">
<span class="md-ellipsis">
Job Queue Throughput
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#database-performance" class="md-nav__link">
<span class="md-ellipsis">
Database Performance
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#monitoring-observability" class="md-nav__link">
<span class="md-ellipsis">
Monitoring &amp; Observability
</span>
</a>
<nav class="md-nav" aria-label="Monitoring &amp; Observability">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#prometheus-metrics" class="md-nav__link">
<span class="md-ellipsis">
Prometheus Metrics
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#grafana-dashboard-panel" class="md-nav__link">
<span class="md-ellipsis">
Grafana Dashboard Panel
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#related-documentation" class="md-nav__link">
<span class="md-ellipsis">
Related Documentation
</span>
</a>
<nav class="md-nav" aria-label="Related Documentation">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#backend-documentation" class="md-nav__link">
<span class="md-ellipsis">
Backend Documentation
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#frontend-documentation" class="md-nav__link">
<span class="md-ellipsis">
Frontend Documentation
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#feature-documentation" class="md-nav__link">
<span class="md-ellipsis">
Feature Documentation
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#next-steps" class="md-nav__link">
<span class="md-ellipsis">
Next Steps
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<nav class="md-path" aria-label="Navigation" >
<ol class="md-path__list">
<li class="md-path__item">
<a href="../../../.." class="md-path__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-path__item">
<a href="../../../" class="md-path__link">
<span class="md-ellipsis">
V2 Documentation
</span>
</a>
</li>
<li class="md-path__item">
<a href="../../" class="md-path__link">
<span class="md-ellipsis">
Features
</span>
</a>
</li>
<li class="md-path__item">
<a href="../" class="md-path__link">
<span class="md-ellipsis">
Media
</span>
</a>
</li>
</ol>
</nav>
<article class="md-content__inner md-typeset">
<a href="https://gitea.bnkops.com/admin/changemaker.lite/src/branch/main/mkdocs/docs/v2/features/media/jobs.md" title="Edit this page" class="md-content__button md-icon" rel="edit">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10 20H6V4h7v5h5v3.1l2-2V8l-6-6H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h4zm10.2-7c.1 0 .3.1.4.2l1.3 1.3c.2.2.2.6 0 .8l-1 1-2.1-2.1 1-1c.1-.1.2-.2.4-.2m0 3.9L14.1 23H12v-2.1l6.1-6.1z"/></svg>
</a>
<a href="https://gitea.bnkops.com/admin/changemaker.lite/src/branch/main/mkdocs/docs/v2/features/media/jobs.md" title="View source of this page" class="md-content__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17 18c.56 0 1 .44 1 1s-.44 1-1 1-1-.44-1-1 .44-1 1-1m0-3c-2.73 0-5.06 1.66-6 4 .94 2.34 3.27 4 6 4s5.06-1.66 6-4c-.94-2.34-3.27-4-6-4m0 6.5a2.5 2.5 0 0 1-2.5-2.5 2.5 2.5 0 0 1 2.5-2.5 2.5 2.5 0 0 1 2.5 2.5 2.5 2.5 0 0 1-2.5 2.5M9.27 20H6V4h7v5h5v4.07c.7.08 1.36.25 2 .49V8l-6-6H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h4.5a8.2 8.2 0 0 1-1.23-2"/></svg>
</a>
<h1 id="media-job-queue-system">Media Job Queue System<a class="headerlink" href="#media-job-queue-system" title="Permanent link">&para;</a></h1>
<h2 id="overview">Overview<a class="headerlink" href="#overview" title="Permanent link">&para;</a></h2>
<p>The Media Job Queue System provides asynchronous background processing for CPU and GPU-intensive video operations. Built on a custom job queue with resource-aware scheduling, it handles everything from directory scanning to AI-powered video analysis while maintaining system stability through resource category management.</p>
<p><strong>Key Features:</strong></p>
<ul>
<li><strong>Resource Categories</strong> — Jobs classified by resource needs (CPU, GPU encode, GPU AI)</li>
<li><strong>Priority Scheduling</strong> — High-priority jobs processed first within same category</li>
<li><strong>Job Types</strong> — 15+ job types (compilation, encoding, digest generation, scene extraction, etc.)</li>
<li><strong>Progress Tracking</strong> — Real-time progress updates (0-100%)</li>
<li><strong>Status Management</strong> — Pending → Queued → Running → Completed/Failed lifecycle</li>
<li><strong>Retry Logic</strong> — Failed jobs can be retried with exponential backoff</li>
<li><strong>Detailed Logging</strong> — Execution logs for debugging and audit trail</li>
<li><strong>Queue Management</strong> — Pause, resume, cancel, and prioritize jobs</li>
<li><strong>VRAM Awareness</strong> — Prevents GPU memory exhaustion by tracking VRAM requirements</li>
</ul>
<p><strong>Access Control:</strong></p>
<ul>
<li>Job viewing/management requires <code>SUPER_ADMIN</code> role</li>
<li>Job creation can be triggered by admins or automated workflows</li>
</ul>
<p><strong>Technology Stack:</strong></p>
<ul>
<li><strong>Database Queue</strong> — PostgreSQL-backed job queue (no BullMQ for media)</li>
<li><strong>Worker Process</strong> — Node.js worker polling queue every 5 seconds</li>
<li><strong>FFmpeg</strong> — Video encoding and compilation</li>
<li><strong>AI Integration</strong> — Future support for scene detection and auto-tagging</li>
</ul>
<hr />
<h2 id="architecture">Architecture<a class="headerlink" href="#architecture" title="Permanent link">&para;</a></h2>
<pre class="mermaid"><code>flowchart TB
subgraph "Job Creation"
A1[Admin Action]
A2[Automated Trigger]
A3[Scheduled Task]
end
subgraph "Job Queue (PostgreSQL)"
Q1[Pending Jobs]
Q2[Queued Jobs]
Q3[Running Jobs]
Q4[Completed/Failed Jobs]
end
subgraph "Worker Process"
W1[Job Poller&lt;br/&gt;Every 5s]
W2[Resource Checker]
W3[Job Executor]
W4[Progress Updater]
end
subgraph "Processors"
P1[CPU Jobs&lt;br/&gt;scan, validate]
P2[GPU Encode&lt;br/&gt;reencode, compile]
P3[GPU AI&lt;br/&gt;digest, tag, scene]
end
subgraph "Results"
R1[Video Records Updated]
R2[New Files Created]
R3[Logs Written]
end
A1 --&gt; Q1
A2 --&gt; Q1
A3 --&gt; Q1
Q1 --&gt; W1
W1 --&gt; W2
W2 --&gt;|Check Resources| Q2
Q2 --&gt; W3
W3 --&gt; P1
W3 --&gt; P2
W3 --&gt; P3
W3 --&gt; W4
W4 --&gt; Q3
P1 --&gt; R1
P2 --&gt; R2
P3 --&gt; R3
Q3 --&gt; Q4
style Q1 fill:#f9f
style Q3 fill:#ff9
style Q4 fill:#9f9</code></pre>
<p><strong>Workflow:</strong></p>
<ol>
<li><strong>Job Creation</strong> — Admin clicks "Re-encode" button, API creates job record</li>
<li><strong>Queue Polling</strong> — Worker checks for pending jobs every 5 seconds</li>
<li><strong>Resource Check</strong> — Worker verifies sufficient VRAM/CPU available</li>
<li><strong>Job Execution</strong> — Worker runs appropriate processor (FFmpeg, AI script, etc.)</li>
<li><strong>Progress Updates</strong> — Worker updates job progress every ~5% completion</li>
<li><strong>Completion</strong> — Worker marks job complete and logs results</li>
<li><strong>Retry on Failure</strong> — Failed jobs can be retried with exponential backoff</li>
</ol>
<hr />
<h2 id="database-model">Database Model<a class="headerlink" href="#database-model" title="Permanent link">&para;</a></h2>
<h3 id="jobs-table-schema">Jobs Table Schema<a class="headerlink" href="#jobs-table-schema" title="Permanent link">&para;</a></h3>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="c1">// api/src/modules/media/db/schema.ts</span>
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="k">export</span><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">jobs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">pgTable</span><span class="p">(</span><span class="s1">&#39;jobs&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a><span class="w"> </span><span class="nx">id</span><span class="o">:</span><span class="w"> </span><span class="kt">uuid</span><span class="p">(</span><span class="s1">&#39;id&#39;</span><span class="p">).</span><span class="nx">primaryKey</span><span class="p">().</span><span class="nx">defaultRandom</span><span class="p">(),</span>
</span><span id="__span-0-4"><a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a>
</span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a><span class="w"> </span><span class="c1">// Job Definition</span>
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a><span class="w"> </span><span class="kr">type</span><span class="o">:</span><span class="w"> </span><span class="nx">text</span><span class="p">(</span><span class="s1">&#39;type&#39;</span><span class="p">).</span><span class="nx">notNull</span><span class="p">(),</span><span class="w"> </span><span class="c1">// JobType enum: compilation, scan, reencode, etc.</span>
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a><span class="w"> </span><span class="nx">status</span><span class="o">:</span><span class="w"> </span><span class="kt">text</span><span class="p">(</span><span class="s1">&#39;status&#39;</span><span class="p">).</span><span class="nx">notNull</span><span class="p">().</span><span class="k">default</span><span class="p">(</span><span class="s1">&#39;pending&#39;</span><span class="p">),</span><span class="w"> </span><span class="c1">// JobStatus enum</span>
</span><span id="__span-0-8"><a id="__codelineno-0-8" name="__codelineno-0-8" href="#__codelineno-0-8"></a><span class="w"> </span><span class="nx">params</span><span class="o">:</span><span class="w"> </span><span class="kt">jsonb</span><span class="p">(</span><span class="s1">&#39;params&#39;</span><span class="p">).</span><span class="nx">$type</span><span class="o">&lt;</span><span class="nx">Record</span><span class="o">&lt;</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">any</span><span class="o">&gt;&gt;</span><span class="p">().</span><span class="nx">notNull</span><span class="p">(),</span><span class="w"> </span><span class="c1">// Job-specific parameters</span>
</span><span id="__span-0-9"><a id="__codelineno-0-9" name="__codelineno-0-9" href="#__codelineno-0-9"></a>
</span><span id="__span-0-10"><a id="__codelineno-0-10" name="__codelineno-0-10" href="#__codelineno-0-10"></a><span class="w"> </span><span class="c1">// Progress Tracking</span>
</span><span id="__span-0-11"><a id="__codelineno-0-11" name="__codelineno-0-11" href="#__codelineno-0-11"></a><span class="w"> </span><span class="nx">progress</span><span class="o">:</span><span class="w"> </span><span class="kt">integer</span><span class="p">(</span><span class="s1">&#39;progress&#39;</span><span class="p">).</span><span class="k">default</span><span class="p">(</span><span class="mf">0</span><span class="p">),</span><span class="w"> </span><span class="c1">// 0-100</span>
</span><span id="__span-0-12"><a id="__codelineno-0-12" name="__codelineno-0-12" href="#__codelineno-0-12"></a><span class="w"> </span><span class="nx">log</span><span class="o">:</span><span class="w"> </span><span class="kt">text</span><span class="p">(</span><span class="s1">&#39;log&#39;</span><span class="p">).</span><span class="k">default</span><span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">),</span><span class="w"> </span><span class="c1">// Execution log (append-only)</span>
</span><span id="__span-0-13"><a id="__codelineno-0-13" name="__codelineno-0-13" href="#__codelineno-0-13"></a>
</span><span id="__span-0-14"><a id="__codelineno-0-14" name="__codelineno-0-14" href="#__codelineno-0-14"></a><span class="w"> </span><span class="c1">// Scheduling</span>
</span><span id="__span-0-15"><a id="__codelineno-0-15" name="__codelineno-0-15" href="#__codelineno-0-15"></a><span class="w"> </span><span class="nx">priority</span><span class="o">:</span><span class="w"> </span><span class="kt">integer</span><span class="p">(</span><span class="s1">&#39;priority&#39;</span><span class="p">).</span><span class="k">default</span><span class="p">(</span><span class="mf">5</span><span class="p">),</span><span class="w"> </span><span class="c1">// 1 (highest) - 10 (lowest)</span>
</span><span id="__span-0-16"><a id="__codelineno-0-16" name="__codelineno-0-16" href="#__codelineno-0-16"></a><span class="w"> </span><span class="nx">queuePosition</span><span class="o">:</span><span class="w"> </span><span class="kt">integer</span><span class="p">(</span><span class="s1">&#39;queue_position&#39;</span><span class="p">),</span><span class="w"> </span><span class="c1">// Position in queue</span>
</span><span id="__span-0-17"><a id="__codelineno-0-17" name="__codelineno-0-17" href="#__codelineno-0-17"></a><span class="w"> </span><span class="nx">waitingReason</span><span class="o">:</span><span class="w"> </span><span class="kt">text</span><span class="p">(</span><span class="s1">&#39;waiting_reason&#39;</span><span class="p">),</span><span class="w"> </span><span class="c1">// Why job is waiting (e.g., &quot;Insufficient VRAM&quot;)</span>
</span><span id="__span-0-18"><a id="__codelineno-0-18" name="__codelineno-0-18" href="#__codelineno-0-18"></a>
</span><span id="__span-0-19"><a id="__codelineno-0-19" name="__codelineno-0-19" href="#__codelineno-0-19"></a><span class="w"> </span><span class="c1">// Resource Management</span>
</span><span id="__span-0-20"><a id="__codelineno-0-20" name="__codelineno-0-20" href="#__codelineno-0-20"></a><span class="w"> </span><span class="nx">resourceCategory</span><span class="o">:</span><span class="w"> </span><span class="kt">text</span><span class="p">(</span><span class="s1">&#39;resource_category&#39;</span><span class="p">).</span><span class="nx">notNull</span><span class="p">(),</span><span class="w"> </span><span class="c1">// cpu|gpu_encode|gpu_ai</span>
</span><span id="__span-0-21"><a id="__codelineno-0-21" name="__codelineno-0-21" href="#__codelineno-0-21"></a><span class="w"> </span><span class="nx">vramRequired</span><span class="o">:</span><span class="w"> </span><span class="kt">integer</span><span class="p">(</span><span class="s1">&#39;vram_required&#39;</span><span class="p">).</span><span class="k">default</span><span class="p">(</span><span class="mf">0</span><span class="p">),</span><span class="w"> </span><span class="c1">// MB of VRAM needed</span>
</span><span id="__span-0-22"><a id="__codelineno-0-22" name="__codelineno-0-22" href="#__codelineno-0-22"></a>
</span><span id="__span-0-23"><a id="__codelineno-0-23" name="__codelineno-0-23" href="#__codelineno-0-23"></a><span class="w"> </span><span class="c1">// Timing</span>
</span><span id="__span-0-24"><a id="__codelineno-0-24" name="__codelineno-0-24" href="#__codelineno-0-24"></a><span class="w"> </span><span class="nx">createdAt</span><span class="o">:</span><span class="w"> </span><span class="kt">timestamp</span><span class="p">(</span><span class="s1">&#39;created_at&#39;</span><span class="p">).</span><span class="nx">defaultNow</span><span class="p">(),</span>
</span><span id="__span-0-25"><a id="__codelineno-0-25" name="__codelineno-0-25" href="#__codelineno-0-25"></a><span class="w"> </span><span class="nx">startedAt</span><span class="o">:</span><span class="w"> </span><span class="kt">timestamp</span><span class="p">(</span><span class="s1">&#39;started_at&#39;</span><span class="p">),</span>
</span><span id="__span-0-26"><a id="__codelineno-0-26" name="__codelineno-0-26" href="#__codelineno-0-26"></a><span class="w"> </span><span class="nx">completedAt</span><span class="o">:</span><span class="w"> </span><span class="kt">timestamp</span><span class="p">(</span><span class="s1">&#39;completed_at&#39;</span><span class="p">),</span>
</span><span id="__span-0-27"><a id="__codelineno-0-27" name="__codelineno-0-27" href="#__codelineno-0-27"></a>
</span><span id="__span-0-28"><a id="__codelineno-0-28" name="__codelineno-0-28" href="#__codelineno-0-28"></a><span class="w"> </span><span class="c1">// Retry Logic</span>
</span><span id="__span-0-29"><a id="__codelineno-0-29" name="__codelineno-0-29" href="#__codelineno-0-29"></a><span class="w"> </span><span class="nx">retryCount</span><span class="o">:</span><span class="w"> </span><span class="kt">integer</span><span class="p">(</span><span class="s1">&#39;retry_count&#39;</span><span class="p">).</span><span class="k">default</span><span class="p">(</span><span class="mf">0</span><span class="p">),</span>
</span><span id="__span-0-30"><a id="__codelineno-0-30" name="__codelineno-0-30" href="#__codelineno-0-30"></a><span class="w"> </span><span class="nx">maxRetries</span><span class="o">:</span><span class="w"> </span><span class="kt">integer</span><span class="p">(</span><span class="s1">&#39;max_retries&#39;</span><span class="p">).</span><span class="k">default</span><span class="p">(</span><span class="mf">3</span><span class="p">),</span>
</span><span id="__span-0-31"><a id="__codelineno-0-31" name="__codelineno-0-31" href="#__codelineno-0-31"></a><span class="w"> </span><span class="nx">retryAfter</span><span class="o">:</span><span class="w"> </span><span class="kt">timestamp</span><span class="p">(</span><span class="s1">&#39;retry_after&#39;</span><span class="p">),</span><span class="w"> </span><span class="c1">// Don&#39;t retry before this time</span>
</span><span id="__span-0-32"><a id="__codelineno-0-32" name="__codelineno-0-32" href="#__codelineno-0-32"></a><span class="p">});</span>
</span></code></pre></div>
<h3 id="job-types-enum">Job Types Enum<a class="headerlink" href="#job-types-enum" title="Permanent link">&para;</a></h3>
<table>
<thead>
<tr>
<th>Type</th>
<th>Resource Category</th>
<th>VRAM (MB)</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>scan</code></td>
<td>cpu</td>
<td>0</td>
<td>Scan directory for new videos</td>
</tr>
<tr>
<td><code>public_scan</code></td>
<td>cpu</td>
<td>0</td>
<td>Scan public gallery directory</td>
</tr>
<tr>
<td><code>validate</code></td>
<td>cpu</td>
<td>0</td>
<td>Validate video metadata (FFprobe)</td>
</tr>
<tr>
<td><code>reencode_streaming</code></td>
<td>gpu_encode</td>
<td>4000</td>
<td>Re-encode for web playback (H.264)</td>
</tr>
<tr>
<td><code>compile_random</code></td>
<td>gpu_encode</td>
<td>2000</td>
<td>Random video compilation</td>
</tr>
<tr>
<td><code>compile_quad</code></td>
<td>gpu_encode</td>
<td>4000</td>
<td>4-up grid compilation</td>
</tr>
<tr>
<td><code>compile_mega</code></td>
<td>gpu_encode</td>
<td>6000</td>
<td>Large multi-video compilation</td>
</tr>
<tr>
<td><code>compile_gif</code></td>
<td>cpu</td>
<td>0</td>
<td>Create GIF from video</td>
</tr>
<tr>
<td><code>digest_generate</code></td>
<td>gpu_ai</td>
<td>8000</td>
<td>AI-powered video digest</td>
</tr>
<tr>
<td><code>clip_generate</code></td>
<td>gpu_ai</td>
<td>6000</td>
<td>Extract clips from digest</td>
</tr>
<tr>
<td><code>highlight_generate</code></td>
<td>gpu_ai</td>
<td>8000</td>
<td>Create highlight reel</td>
</tr>
<tr>
<td><code>tag_generation</code></td>
<td>gpu_ai</td>
<td>6000</td>
<td>AI auto-tagging</td>
</tr>
<tr>
<td><code>scene_extract</code></td>
<td>gpu_ai</td>
<td>8000</td>
<td>Scene detection and extraction</td>
</tr>
<tr>
<td><code>thumbnail_generate</code></td>
<td>cpu</td>
<td>0</td>
<td>Generate thumbnail from video</td>
</tr>
<tr>
<td><code>move_to_library</code></td>
<td>cpu</td>
<td>0</td>
<td>Move video from inbox to target directory</td>
</tr>
</tbody>
</table>
<h3 id="job-status-enum">Job Status Enum<a class="headerlink" href="#job-status-enum" title="Permanent link">&para;</a></h3>
<table>
<thead>
<tr>
<th>Status</th>
<th>Description</th>
<th>Final State</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>pending</code></td>
<td>Waiting to be picked up by worker</td>
<td>No</td>
</tr>
<tr>
<td><code>queued</code></td>
<td>Selected by worker, waiting for resources</td>
<td>No</td>
</tr>
<tr>
<td><code>running</code></td>
<td>Currently executing</td>
<td>No</td>
</tr>
<tr>
<td><code>completed</code></td>
<td>Finished successfully</td>
<td>Yes</td>
</tr>
<tr>
<td><code>failed</code></td>
<td>Execution failed (see log for details)</td>
<td>Yes</td>
</tr>
<tr>
<td><code>cancelled</code></td>
<td>Manually cancelled by admin</td>
<td>Yes</td>
</tr>
<tr>
<td><code>paused</code></td>
<td>Temporarily paused (can be resumed)</td>
<td>No</td>
</tr>
</tbody>
</table>
<h3 id="resource-categories">Resource Categories<a class="headerlink" href="#resource-categories" title="Permanent link">&para;</a></h3>
<table>
<thead>
<tr>
<th>Category</th>
<th>Typical VRAM</th>
<th>Concurrent Limit</th>
<th>Use Cases</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>cpu</code></td>
<td>0 MB</td>
<td>5</td>
<td>Scanning, validation, simple encodes, GIF creation</td>
</tr>
<tr>
<td><code>gpu_encode</code></td>
<td>2-6 GB</td>
<td>2</td>
<td>Video re-encoding, compilation, format conversion</td>
</tr>
<tr>
<td><code>gpu_ai</code></td>
<td>6-12 GB</td>
<td>1</td>
<td>AI tagging, scene detection, digest generation, highlight extraction</td>
</tr>
</tbody>
</table>
<p><strong>VRAM Management:</strong></p>
<p>Worker tracks total VRAM usage across running jobs:</p>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-1-1"><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="kd">const</span><span class="w"> </span><span class="nx">runningJobs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">db</span><span class="p">.</span><span class="nx">select</span><span class="p">().</span><span class="kr">from</span><span class="p">(</span><span class="nx">jobs</span><span class="p">).</span><span class="nx">where</span><span class="p">(</span><span class="nx">eq</span><span class="p">(</span><span class="nx">jobs</span><span class="p">.</span><span class="nx">status</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;running&#39;</span><span class="p">));</span>
</span><span id="__span-1-2"><a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a><span class="kd">const</span><span class="w"> </span><span class="nx">totalVramUsed</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">runningJobs</span><span class="p">.</span><span class="nx">reduce</span><span class="p">((</span><span class="nx">sum</span><span class="p">,</span><span class="w"> </span><span class="nx">job</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="nx">sum</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="nx">job</span><span class="p">.</span><span class="nx">vramRequired</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="mf">0</span><span class="p">),</span><span class="w"> </span><span class="mf">0</span><span class="p">);</span>
</span><span id="__span-1-3"><a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a>
</span><span id="__span-1-4"><a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a><span class="c1">// Only start new job if VRAM available</span>
</span><span id="__span-1-5"><a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a><span class="kd">const</span><span class="w"> </span><span class="nx">TOTAL_VRAM</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">16000</span><span class="p">;</span><span class="w"> </span><span class="c1">// 16GB GPU</span>
</span><span id="__span-1-6"><a id="__codelineno-1-6" name="__codelineno-1-6" href="#__codelineno-1-6"></a><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">totalVramUsed</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">newJob</span><span class="p">.</span><span class="nx">vramRequired</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="nx">TOTAL_VRAM</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-1-7"><a id="__codelineno-1-7" name="__codelineno-1-7" href="#__codelineno-1-7"></a><span class="w"> </span><span class="nx">startJob</span><span class="p">(</span><span class="nx">newJob</span><span class="p">);</span>
</span><span id="__span-1-8"><a id="__codelineno-1-8" name="__codelineno-1-8" href="#__codelineno-1-8"></a><span class="p">}</span>
</span></code></pre></div>
<hr />
<h2 id="api-endpoints">API Endpoints<a class="headerlink" href="#api-endpoints" title="Permanent link">&para;</a></h2>
<p>All endpoints require <code>SUPER_ADMIN</code> role.</p>
<h3 id="list-jobs">List Jobs<a class="headerlink" href="#list-jobs" title="Permanent link">&para;</a></h3>
<div class="language-http highlight"><pre><span></span><code><span id="__span-2-1"><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><span class="err">GET /api/media/jobs</span>
</span></code></pre></div>
<p><strong>Query Parameters:</strong></p>
<table>
<thead>
<tr>
<th>Parameter</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>page</code></td>
<td>number</td>
<td>1</td>
<td>Page number</td>
</tr>
<tr>
<td><code>limit</code></td>
<td>number</td>
<td>20</td>
<td>Results per page</td>
</tr>
<tr>
<td><code>status</code></td>
<td>string</td>
<td>-</td>
<td>Filter by status (pending, running, completed, failed)</td>
</tr>
<tr>
<td><code>type</code></td>
<td>string</td>
<td>-</td>
<td>Filter by job type</td>
</tr>
<tr>
<td><code>resourceCategory</code></td>
<td>string</td>
<td>-</td>
<td>Filter by resource category</td>
</tr>
</tbody>
</table>
<p><strong>Response:</strong></p>
<div class="language-json highlight"><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="p">{</span>
</span><span id="__span-3-2"><a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a><span class="w"> </span><span class="nt">&quot;data&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
</span><span id="__span-3-3"><a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="w"> </span><span class="p">{</span>
</span><span id="__span-3-4"><a id="__codelineno-3-4" name="__codelineno-3-4" href="#__codelineno-3-4"></a><span class="w"> </span><span class="nt">&quot;id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;550e8400-e29b-41d4-a716-446655440000&quot;</span><span class="p">,</span>
</span><span id="__span-3-5"><a id="__codelineno-3-5" name="__codelineno-3-5" href="#__codelineno-3-5"></a><span class="w"> </span><span class="nt">&quot;type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;reencode_streaming&quot;</span><span class="p">,</span>
</span><span id="__span-3-6"><a id="__codelineno-3-6" name="__codelineno-3-6" href="#__codelineno-3-6"></a><span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;running&quot;</span><span class="p">,</span>
</span><span id="__span-3-7"><a id="__codelineno-3-7" name="__codelineno-3-7" href="#__codelineno-3-7"></a><span class="w"> </span><span class="nt">&quot;progress&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">45</span><span class="p">,</span>
</span><span id="__span-3-8"><a id="__codelineno-3-8" name="__codelineno-3-8" href="#__codelineno-3-8"></a><span class="w"> </span><span class="nt">&quot;resourceCategory&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;gpu_encode&quot;</span><span class="p">,</span>
</span><span id="__span-3-9"><a id="__codelineno-3-9" name="__codelineno-3-9" href="#__codelineno-3-9"></a><span class="w"> </span><span class="nt">&quot;vramRequired&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">4000</span><span class="p">,</span>
</span><span id="__span-3-10"><a id="__codelineno-3-10" name="__codelineno-3-10" href="#__codelineno-3-10"></a><span class="w"> </span><span class="nt">&quot;priority&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">5</span><span class="p">,</span>
</span><span id="__span-3-11"><a id="__codelineno-3-11" name="__codelineno-3-11" href="#__codelineno-3-11"></a><span class="w"> </span><span class="nt">&quot;params&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-3-12"><a id="__codelineno-3-12" name="__codelineno-3-12" href="#__codelineno-3-12"></a><span class="w"> </span><span class="nt">&quot;videoId&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;660e8400-e29b-41d4-a716-446655440001&quot;</span><span class="p">,</span>
</span><span id="__span-3-13"><a id="__codelineno-3-13" name="__codelineno-3-13" href="#__codelineno-3-13"></a><span class="w"> </span><span class="nt">&quot;targetBitrate&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">2000</span>
</span><span id="__span-3-14"><a id="__codelineno-3-14" name="__codelineno-3-14" href="#__codelineno-3-14"></a><span class="w"> </span><span class="p">},</span>
</span><span id="__span-3-15"><a id="__codelineno-3-15" name="__codelineno-3-15" href="#__codelineno-3-15"></a><span class="w"> </span><span class="nt">&quot;startedAt&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;2026-02-13T10:30:00Z&quot;</span><span class="p">,</span>
</span><span id="__span-3-16"><a id="__codelineno-3-16" name="__codelineno-3-16" href="#__codelineno-3-16"></a><span class="w"> </span><span class="nt">&quot;createdAt&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;2026-02-13T10:25:00Z&quot;</span>
</span><span id="__span-3-17"><a id="__codelineno-3-17" name="__codelineno-3-17" href="#__codelineno-3-17"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-3-18"><a id="__codelineno-3-18" name="__codelineno-3-18" href="#__codelineno-3-18"></a><span class="w"> </span><span class="p">],</span>
</span><span id="__span-3-19"><a id="__codelineno-3-19" name="__codelineno-3-19" href="#__codelineno-3-19"></a><span class="w"> </span><span class="nt">&quot;pagination&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-3-20"><a id="__codelineno-3-20" name="__codelineno-3-20" href="#__codelineno-3-20"></a><span class="w"> </span><span class="nt">&quot;page&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span>
</span><span id="__span-3-21"><a id="__codelineno-3-21" name="__codelineno-3-21" href="#__codelineno-3-21"></a><span class="w"> </span><span class="nt">&quot;limit&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">20</span><span class="p">,</span>
</span><span id="__span-3-22"><a id="__codelineno-3-22" name="__codelineno-3-22" href="#__codelineno-3-22"></a><span class="w"> </span><span class="nt">&quot;total&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">156</span><span class="p">,</span>
</span><span id="__span-3-23"><a id="__codelineno-3-23" name="__codelineno-3-23" href="#__codelineno-3-23"></a><span class="w"> </span><span class="nt">&quot;totalPages&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">8</span>
</span><span id="__span-3-24"><a id="__codelineno-3-24" name="__codelineno-3-24" href="#__codelineno-3-24"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-3-25"><a id="__codelineno-3-25" name="__codelineno-3-25" href="#__codelineno-3-25"></a><span class="p">}</span>
</span></code></pre></div>
<hr />
<h3 id="get-job-details">Get Job Details<a class="headerlink" href="#get-job-details" title="Permanent link">&para;</a></h3>
<div class="language-http highlight"><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="err">GET /api/media/jobs/:id</span>
</span></code></pre></div>
<p><strong>Response:</strong></p>
<div class="language-json highlight"><pre><span></span><code><span id="__span-5-1"><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><span class="p">{</span>
</span><span id="__span-5-2"><a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a><span class="w"> </span><span class="nt">&quot;id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;550e8400-e29b-41d4-a716-446655440000&quot;</span><span class="p">,</span>
</span><span id="__span-5-3"><a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a><span class="w"> </span><span class="nt">&quot;type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;reencode_streaming&quot;</span><span class="p">,</span>
</span><span id="__span-5-4"><a id="__codelineno-5-4" name="__codelineno-5-4" href="#__codelineno-5-4"></a><span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;completed&quot;</span><span class="p">,</span>
</span><span id="__span-5-5"><a id="__codelineno-5-5" name="__codelineno-5-5" href="#__codelineno-5-5"></a><span class="w"> </span><span class="nt">&quot;progress&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="p">,</span>
</span><span id="__span-5-6"><a id="__codelineno-5-6" name="__codelineno-5-6" href="#__codelineno-5-6"></a><span class="w"> </span><span class="nt">&quot;log&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Starting re-encode...\nFFmpeg command: ffmpeg -i input.mp4 -c:v h264 -preset medium -crf 23 output.mp4\nProgress: 25%\nProgress: 50%\nProgress: 75%\nProgress: 100%\nCompleted successfully&quot;</span><span class="p">,</span>
</span><span id="__span-5-7"><a id="__codelineno-5-7" name="__codelineno-5-7" href="#__codelineno-5-7"></a><span class="w"> </span><span class="nt">&quot;params&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-5-8"><a id="__codelineno-5-8" name="__codelineno-5-8" href="#__codelineno-5-8"></a><span class="w"> </span><span class="nt">&quot;videoId&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;660e8400-e29b-41d4-a716-446655440001&quot;</span><span class="p">,</span>
</span><span id="__span-5-9"><a id="__codelineno-5-9" name="__codelineno-5-9" href="#__codelineno-5-9"></a><span class="w"> </span><span class="nt">&quot;inputPath&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;inbox/original.mp4&quot;</span><span class="p">,</span>
</span><span id="__span-5-10"><a id="__codelineno-5-10" name="__codelineno-5-10" href="#__codelineno-5-10"></a><span class="w"> </span><span class="nt">&quot;outputPath&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;playback/encoded.mp4&quot;</span><span class="p">,</span>
</span><span id="__span-5-11"><a id="__codelineno-5-11" name="__codelineno-5-11" href="#__codelineno-5-11"></a><span class="w"> </span><span class="nt">&quot;targetBitrate&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">2000</span>
</span><span id="__span-5-12"><a id="__codelineno-5-12" name="__codelineno-5-12" href="#__codelineno-5-12"></a><span class="w"> </span><span class="p">},</span>
</span><span id="__span-5-13"><a id="__codelineno-5-13" name="__codelineno-5-13" href="#__codelineno-5-13"></a><span class="w"> </span><span class="nt">&quot;resourceCategory&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;gpu_encode&quot;</span><span class="p">,</span>
</span><span id="__span-5-14"><a id="__codelineno-5-14" name="__codelineno-5-14" href="#__codelineno-5-14"></a><span class="w"> </span><span class="nt">&quot;vramRequired&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">4000</span><span class="p">,</span>
</span><span id="__span-5-15"><a id="__codelineno-5-15" name="__codelineno-5-15" href="#__codelineno-5-15"></a><span class="w"> </span><span class="nt">&quot;priority&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">5</span><span class="p">,</span>
</span><span id="__span-5-16"><a id="__codelineno-5-16" name="__codelineno-5-16" href="#__codelineno-5-16"></a><span class="w"> </span><span class="nt">&quot;retryCount&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span>
</span><span id="__span-5-17"><a id="__codelineno-5-17" name="__codelineno-5-17" href="#__codelineno-5-17"></a><span class="w"> </span><span class="nt">&quot;maxRetries&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span>
</span><span id="__span-5-18"><a id="__codelineno-5-18" name="__codelineno-5-18" href="#__codelineno-5-18"></a><span class="w"> </span><span class="nt">&quot;createdAt&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;2026-02-13T10:25:00Z&quot;</span><span class="p">,</span>
</span><span id="__span-5-19"><a id="__codelineno-5-19" name="__codelineno-5-19" href="#__codelineno-5-19"></a><span class="w"> </span><span class="nt">&quot;startedAt&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;2026-02-13T10:30:00Z&quot;</span><span class="p">,</span>
</span><span id="__span-5-20"><a id="__codelineno-5-20" name="__codelineno-5-20" href="#__codelineno-5-20"></a><span class="w"> </span><span class="nt">&quot;completedAt&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;2026-02-13T10:45:00Z&quot;</span>
</span><span id="__span-5-21"><a id="__codelineno-5-21" name="__codelineno-5-21" href="#__codelineno-5-21"></a><span class="p">}</span>
</span></code></pre></div>
<hr />
<h3 id="create-job">Create Job<a class="headerlink" href="#create-job" title="Permanent link">&para;</a></h3>
<div class="language-http highlight"><pre><span></span><code><span id="__span-6-1"><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a><span class="err">POST /api/media/jobs</span>
</span></code></pre></div>
<p><strong>Request Body:</strong></p>
<div class="language-json highlight"><pre><span></span><code><span id="__span-7-1"><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a><span class="p">{</span>
</span><span id="__span-7-2"><a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a><span class="w"> </span><span class="nt">&quot;type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;reencode_streaming&quot;</span><span class="p">,</span>
</span><span id="__span-7-3"><a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a><span class="w"> </span><span class="nt">&quot;params&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-7-4"><a id="__codelineno-7-4" name="__codelineno-7-4" href="#__codelineno-7-4"></a><span class="w"> </span><span class="nt">&quot;videoId&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;660e8400-e29b-41d4-a716-446655440001&quot;</span><span class="p">,</span>
</span><span id="__span-7-5"><a id="__codelineno-7-5" name="__codelineno-7-5" href="#__codelineno-7-5"></a><span class="w"> </span><span class="nt">&quot;targetBitrate&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">2000</span>
</span><span id="__span-7-6"><a id="__codelineno-7-6" name="__codelineno-7-6" href="#__codelineno-7-6"></a><span class="w"> </span><span class="p">},</span>
</span><span id="__span-7-7"><a id="__codelineno-7-7" name="__codelineno-7-7" href="#__codelineno-7-7"></a><span class="w"> </span><span class="nt">&quot;priority&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">5</span><span class="p">,</span>
</span><span id="__span-7-8"><a id="__codelineno-7-8" name="__codelineno-7-8" href="#__codelineno-7-8"></a><span class="w"> </span><span class="nt">&quot;resourceCategory&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;gpu_encode&quot;</span><span class="p">,</span>
</span><span id="__span-7-9"><a id="__codelineno-7-9" name="__codelineno-7-9" href="#__codelineno-7-9"></a><span class="w"> </span><span class="nt">&quot;vramRequired&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">4000</span>
</span><span id="__span-7-10"><a id="__codelineno-7-10" name="__codelineno-7-10" href="#__codelineno-7-10"></a><span class="p">}</span>
</span></code></pre></div>
<p><strong>Response:</strong></p>
<div class="language-json highlight"><pre><span></span><code><span id="__span-8-1"><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a><span class="p">{</span>
</span><span id="__span-8-2"><a id="__codelineno-8-2" name="__codelineno-8-2" href="#__codelineno-8-2"></a><span class="w"> </span><span class="nt">&quot;id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;770e8400-e29b-41d4-a716-446655440002&quot;</span><span class="p">,</span>
</span><span id="__span-8-3"><a id="__codelineno-8-3" name="__codelineno-8-3" href="#__codelineno-8-3"></a><span class="w"> </span><span class="nt">&quot;type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;reencode_streaming&quot;</span><span class="p">,</span>
</span><span id="__span-8-4"><a id="__codelineno-8-4" name="__codelineno-8-4" href="#__codelineno-8-4"></a><span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;pending&quot;</span><span class="p">,</span>
</span><span id="__span-8-5"><a id="__codelineno-8-5" name="__codelineno-8-5" href="#__codelineno-8-5"></a><span class="w"> </span><span class="nt">&quot;progress&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span>
</span><span id="__span-8-6"><a id="__codelineno-8-6" name="__codelineno-8-6" href="#__codelineno-8-6"></a><span class="w"> </span><span class="nt">&quot;createdAt&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;2026-02-13T11:00:00Z&quot;</span>
</span><span id="__span-8-7"><a id="__codelineno-8-7" name="__codelineno-8-7" href="#__codelineno-8-7"></a><span class="p">}</span>
</span></code></pre></div>
<hr />
<h3 id="retry-failed-job">Retry Failed Job<a class="headerlink" href="#retry-failed-job" title="Permanent link">&para;</a></h3>
<div class="language-http highlight"><pre><span></span><code><span id="__span-9-1"><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a><span class="err">POST /api/media/jobs/:id/retry</span>
</span></code></pre></div>
<p><strong>Response:</strong></p>
<div class="language-json highlight"><pre><span></span><code><span id="__span-10-1"><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="p">{</span>
</span><span id="__span-10-2"><a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a><span class="w"> </span><span class="nt">&quot;id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;550e8400-e29b-41d4-a716-446655440000&quot;</span><span class="p">,</span>
</span><span id="__span-10-3"><a id="__codelineno-10-3" name="__codelineno-10-3" href="#__codelineno-10-3"></a><span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;pending&quot;</span><span class="p">,</span>
</span><span id="__span-10-4"><a id="__codelineno-10-4" name="__codelineno-10-4" href="#__codelineno-10-4"></a><span class="w"> </span><span class="nt">&quot;retryCount&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span>
</span><span id="__span-10-5"><a id="__codelineno-10-5" name="__codelineno-10-5" href="#__codelineno-10-5"></a><span class="w"> </span><span class="nt">&quot;retryAfter&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span>
</span><span id="__span-10-6"><a id="__codelineno-10-6" name="__codelineno-10-6" href="#__codelineno-10-6"></a><span class="w"> </span><span class="nt">&quot;log&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Starting re-encode...\n[Previous logs...]\n--- RETRY ATTEMPT 1 ---\n&quot;</span>
</span><span id="__span-10-7"><a id="__codelineno-10-7" name="__codelineno-10-7" href="#__codelineno-10-7"></a><span class="p">}</span>
</span></code></pre></div>
<p><strong>Retry Logic:</strong></p>
<ul>
<li>Failed jobs can be retried up to <code>maxRetries</code> times (default: 3)</li>
<li>Exponential backoff: wait <code>2^retryCount</code> minutes before retry</li>
<li>Retry resets status to <code>pending</code> and appends retry marker to log</li>
</ul>
<hr />
<h3 id="cancel-job">Cancel Job<a class="headerlink" href="#cancel-job" title="Permanent link">&para;</a></h3>
<div class="language-http highlight"><pre><span></span><code><span id="__span-11-1"><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a><span class="err">POST /api/media/jobs/:id/cancel</span>
</span></code></pre></div>
<p><strong>Response:</strong></p>
<div class="language-json highlight"><pre><span></span><code><span id="__span-12-1"><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a><span class="p">{</span>
</span><span id="__span-12-2"><a id="__codelineno-12-2" name="__codelineno-12-2" href="#__codelineno-12-2"></a><span class="w"> </span><span class="nt">&quot;id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;550e8400-e29b-41d4-a716-446655440000&quot;</span><span class="p">,</span>
</span><span id="__span-12-3"><a id="__codelineno-12-3" name="__codelineno-12-3" href="#__codelineno-12-3"></a><span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;cancelled&quot;</span><span class="p">,</span>
</span><span id="__span-12-4"><a id="__codelineno-12-4" name="__codelineno-12-4" href="#__codelineno-12-4"></a><span class="w"> </span><span class="nt">&quot;log&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Starting re-encode...\nProgress: 25%\n--- JOB CANCELLED BY ADMIN ---&quot;</span>
</span><span id="__span-12-5"><a id="__codelineno-12-5" name="__codelineno-12-5" href="#__codelineno-12-5"></a><span class="p">}</span>
</span></code></pre></div>
<p><strong>Notes:</strong></p>
<ul>
<li>Running jobs cannot be cancelled immediately (worker must finish current chunk)</li>
<li>Pending/queued jobs cancelled instantly</li>
</ul>
<hr />
<h3 id="pauseresume-job">Pause/Resume Job<a class="headerlink" href="#pauseresume-job" title="Permanent link">&para;</a></h3>
<div class="language-http highlight"><pre><span></span><code><span id="__span-13-1"><a id="__codelineno-13-1" name="__codelineno-13-1" href="#__codelineno-13-1"></a><span class="err">POST /api/media/jobs/:id/pause</span>
</span><span id="__span-13-2"><a id="__codelineno-13-2" name="__codelineno-13-2" href="#__codelineno-13-2"></a><span class="err">POST /api/media/jobs/:id/resume</span>
</span></code></pre></div>
<p><strong>Pause Response:</strong></p>
<div class="language-json highlight"><pre><span></span><code><span id="__span-14-1"><a id="__codelineno-14-1" name="__codelineno-14-1" href="#__codelineno-14-1"></a><span class="p">{</span>
</span><span id="__span-14-2"><a id="__codelineno-14-2" name="__codelineno-14-2" href="#__codelineno-14-2"></a><span class="w"> </span><span class="nt">&quot;id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;550e8400-e29b-41d4-a716-446655440000&quot;</span><span class="p">,</span>
</span><span id="__span-14-3"><a id="__codelineno-14-3" name="__codelineno-14-3" href="#__codelineno-14-3"></a><span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;paused&quot;</span>
</span><span id="__span-14-4"><a id="__codelineno-14-4" name="__codelineno-14-4" href="#__codelineno-14-4"></a><span class="p">}</span>
</span></code></pre></div>
<p><strong>Resume Response:</strong></p>
<div class="language-json highlight"><pre><span></span><code><span id="__span-15-1"><a id="__codelineno-15-1" name="__codelineno-15-1" href="#__codelineno-15-1"></a><span class="p">{</span>
</span><span id="__span-15-2"><a id="__codelineno-15-2" name="__codelineno-15-2" href="#__codelineno-15-2"></a><span class="w"> </span><span class="nt">&quot;id&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;550e8400-e29b-41d4-a716-446655440000&quot;</span><span class="p">,</span>
</span><span id="__span-15-3"><a id="__codelineno-15-3" name="__codelineno-15-3" href="#__codelineno-15-3"></a><span class="w"> </span><span class="nt">&quot;status&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;pending&quot;</span>
</span><span id="__span-15-4"><a id="__codelineno-15-4" name="__codelineno-15-4" href="#__codelineno-15-4"></a><span class="p">}</span>
</span></code></pre></div>
<hr />
<h3 id="queue-statistics">Queue Statistics<a class="headerlink" href="#queue-statistics" title="Permanent link">&para;</a></h3>
<div class="language-http highlight"><pre><span></span><code><span id="__span-16-1"><a id="__codelineno-16-1" name="__codelineno-16-1" href="#__codelineno-16-1"></a><span class="err">GET /api/media/jobs/stats</span>
</span></code></pre></div>
<p><strong>Response:</strong></p>
<div class="language-json highlight"><pre><span></span><code><span id="__span-17-1"><a id="__codelineno-17-1" name="__codelineno-17-1" href="#__codelineno-17-1"></a><span class="p">{</span>
</span><span id="__span-17-2"><a id="__codelineno-17-2" name="__codelineno-17-2" href="#__codelineno-17-2"></a><span class="w"> </span><span class="nt">&quot;pending&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">12</span><span class="p">,</span>
</span><span id="__span-17-3"><a id="__codelineno-17-3" name="__codelineno-17-3" href="#__codelineno-17-3"></a><span class="w"> </span><span class="nt">&quot;queued&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span>
</span><span id="__span-17-4"><a id="__codelineno-17-4" name="__codelineno-17-4" href="#__codelineno-17-4"></a><span class="w"> </span><span class="nt">&quot;running&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span>
</span><span id="__span-17-5"><a id="__codelineno-17-5" name="__codelineno-17-5" href="#__codelineno-17-5"></a><span class="w"> </span><span class="nt">&quot;completed&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1458</span><span class="p">,</span>
</span><span id="__span-17-6"><a id="__codelineno-17-6" name="__codelineno-17-6" href="#__codelineno-17-6"></a><span class="w"> </span><span class="nt">&quot;failed&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">23</span><span class="p">,</span>
</span><span id="__span-17-7"><a id="__codelineno-17-7" name="__codelineno-17-7" href="#__codelineno-17-7"></a><span class="w"> </span><span class="nt">&quot;paused&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span>
</span><span id="__span-17-8"><a id="__codelineno-17-8" name="__codelineno-17-8" href="#__codelineno-17-8"></a><span class="w"> </span><span class="nt">&quot;totalVramUsed&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">12000</span><span class="p">,</span>
</span><span id="__span-17-9"><a id="__codelineno-17-9" name="__codelineno-17-9" href="#__codelineno-17-9"></a><span class="w"> </span><span class="nt">&quot;totalVramAvailable&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">16000</span><span class="p">,</span>
</span><span id="__span-17-10"><a id="__codelineno-17-10" name="__codelineno-17-10" href="#__codelineno-17-10"></a><span class="w"> </span><span class="nt">&quot;averageProcessingTime&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">245</span><span class="p">,</span>
</span><span id="__span-17-11"><a id="__codelineno-17-11" name="__codelineno-17-11" href="#__codelineno-17-11"></a><span class="w"> </span><span class="nt">&quot;jobsByType&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-17-12"><a id="__codelineno-17-12" name="__codelineno-17-12" href="#__codelineno-17-12"></a><span class="w"> </span><span class="nt">&quot;reencode_streaming&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">45</span><span class="p">,</span>
</span><span id="__span-17-13"><a id="__codelineno-17-13" name="__codelineno-17-13" href="#__codelineno-17-13"></a><span class="w"> </span><span class="nt">&quot;scan&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">8</span><span class="p">,</span>
</span><span id="__span-17-14"><a id="__codelineno-17-14" name="__codelineno-17-14" href="#__codelineno-17-14"></a><span class="w"> </span><span class="nt">&quot;compile_random&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">12</span>
</span><span id="__span-17-15"><a id="__codelineno-17-15" name="__codelineno-17-15" href="#__codelineno-17-15"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-17-16"><a id="__codelineno-17-16" name="__codelineno-17-16" href="#__codelineno-17-16"></a><span class="p">}</span>
</span></code></pre></div>
<hr />
<h2 id="admin-workflow">Admin Workflow<a class="headerlink" href="#admin-workflow" title="Permanent link">&para;</a></h2>
<h3 id="viewing-job-queue">Viewing Job Queue<a class="headerlink" href="#viewing-job-queue" title="Permanent link">&para;</a></h3>
<ol>
<li>Navigate to <strong>Media → Jobs</strong> in admin sidebar</li>
<li>Table displays all jobs with:</li>
<li>Job type icon</li>
<li>Status badge (color-coded)</li>
<li>Progress bar</li>
<li>Priority indicator</li>
<li>Resource category</li>
<li>Created/started/completed times</li>
<li>Use filters at top:</li>
<li><strong>Status</strong> dropdown (All / Pending / Running / Completed / Failed)</li>
<li><strong>Type</strong> dropdown (job type)</li>
<li><strong>Resource</strong> dropdown (CPU / GPU Encode / GPU AI)</li>
</ol>
<h3 id="creating-jobs-manually">Creating Jobs Manually<a class="headerlink" href="#creating-jobs-manually" title="Permanent link">&para;</a></h3>
<p><strong>Option 1: From Library Page</strong></p>
<ol>
<li>Select video in library table</li>
<li>Click <strong>"Actions"</strong> dropdown</li>
<li>Select action:</li>
<li>"Re-encode for Streaming"</li>
<li>"Generate Thumbnail"</li>
<li>"Validate Metadata"</li>
<li>"Move to Directory"</li>
<li>Confirm job creation</li>
<li>Redirected to Jobs page showing new job</li>
</ol>
<p><strong>Option 2: From Jobs Page</strong></p>
<ol>
<li>Click <strong>"Create Job"</strong> button</li>
<li>Modal opens with form:</li>
<li><strong>Type</strong> dropdown (15+ job types)</li>
<li><strong>Video</strong> selector (search by title/filename)</li>
<li><strong>Priority</strong> slider (1-10)</li>
<li><strong>Parameters</strong> JSON editor (advanced)</li>
<li>Click <strong>"Create"</strong></li>
<li>Job appears in pending queue</li>
</ol>
<h3 id="monitoring-job-progress">Monitoring Job Progress<a class="headerlink" href="#monitoring-job-progress" title="Permanent link">&para;</a></h3>
<p><strong>Real-Time Updates:</strong></p>
<ol>
<li>Jobs page polls API every 2 seconds for running jobs</li>
<li>Progress bars update smoothly (0-100%)</li>
<li>Status badges change color:</li>
<li>Grey: Pending</li>
<li>Blue: Queued</li>
<li>Yellow: Running</li>
<li>Green: Completed</li>
<li>Red: Failed</li>
</ol>
<p><strong>Detailed Logs:</strong></p>
<ol>
<li>Click job row to expand details panel</li>
<li>View execution log in monospace text area</li>
<li>Log updates in real-time while job running</li>
<li>Example log output:</li>
</ol>
<div class="language-text highlight"><pre><span></span><code><span id="__span-18-1"><a id="__codelineno-18-1" name="__codelineno-18-1" href="#__codelineno-18-1"></a>[2026-02-13 10:30:15] Starting re-encode job
</span><span id="__span-18-2"><a id="__codelineno-18-2" name="__codelineno-18-2" href="#__codelineno-18-2"></a>[2026-02-13 10:30:16] Input: /media/local/inbox/original.mp4
</span><span id="__span-18-3"><a id="__codelineno-18-3" name="__codelineno-18-3" href="#__codelineno-18-3"></a>[2026-02-13 10:30:16] Output: /media/local/playback/encoded.mp4
</span><span id="__span-18-4"><a id="__codelineno-18-4" name="__codelineno-18-4" href="#__codelineno-18-4"></a>[2026-02-13 10:30:17] FFmpeg command: ffmpeg -i /media/local/inbox/original.mp4 -c:v libx264 -preset medium -crf 23 -c:a aac -b:a 128k /media/local/playback/encoded.mp4
</span><span id="__span-18-5"><a id="__codelineno-18-5" name="__codelineno-18-5" href="#__codelineno-18-5"></a>[2026-02-13 10:30:20] Progress: 5%
</span><span id="__span-18-6"><a id="__codelineno-18-6" name="__codelineno-18-6" href="#__codelineno-18-6"></a>[2026-02-13 10:30:25] Progress: 15%
</span><span id="__span-18-7"><a id="__codelineno-18-7" name="__codelineno-18-7" href="#__codelineno-18-7"></a>[2026-02-13 10:30:30] Progress: 25%
</span><span id="__span-18-8"><a id="__codelineno-18-8" name="__codelineno-18-8" href="#__codelineno-18-8"></a>...
</span><span id="__span-18-9"><a id="__codelineno-18-9" name="__codelineno-18-9" href="#__codelineno-18-9"></a>[2026-02-13 10:45:00] Progress: 100%
</span><span id="__span-18-10"><a id="__codelineno-18-10" name="__codelineno-18-10" href="#__codelineno-18-10"></a>[2026-02-13 10:45:01] Re-encode completed successfully
</span><span id="__span-18-11"><a id="__codelineno-18-11" name="__codelineno-18-11" href="#__codelineno-18-11"></a>[2026-02-13 10:45:02] Output file size: 25.3 MB
</span></code></pre></div>
<h3 id="retrying-failed-jobs">Retrying Failed Jobs<a class="headerlink" href="#retrying-failed-jobs" title="Permanent link">&para;</a></h3>
<ol>
<li>Filter for <strong>Failed</strong> jobs</li>
<li>Click job row to view error log</li>
<li>Identify failure reason (e.g., "FFmpeg error: codec not supported")</li>
<li>Fix underlying issue (install codec, fix file path, etc.)</li>
<li>Click <strong>"Retry"</strong> button</li>
<li>Job resets to pending status</li>
<li>Worker picks up job again</li>
</ol>
<p><strong>Auto-Retry:</strong></p>
<p>Jobs automatically retry up to 3 times with exponential backoff:</p>
<ul>
<li>1<sup>st</sup> retry: after 2 minutes</li>
<li>2<sup>nd</sup> retry: after 4 minutes</li>
<li>3<sup>rd</sup> retry: after 8 minutes</li>
</ul>
<h3 id="cancelling-jobs">Cancelling Jobs<a class="headerlink" href="#cancelling-jobs" title="Permanent link">&para;</a></h3>
<ol>
<li>Find job in pending/queued/running state</li>
<li>Click <strong>"Cancel"</strong> button</li>
<li>Confirm cancellation dialog</li>
<li>Job marked as cancelled</li>
<li>If running, worker stops after current chunk completes</li>
</ol>
<h3 id="pausingresuming-jobs">Pausing/Resuming Jobs<a class="headerlink" href="#pausingresuming-jobs" title="Permanent link">&para;</a></h3>
<p><strong>Use Case:</strong> Temporarily stop low-priority jobs to free resources for urgent tasks</p>
<ol>
<li>Select low-priority pending job</li>
<li>Click <strong>"Pause"</strong> button</li>
<li>Job status changes to paused (greyed out)</li>
<li>Worker skips paused jobs</li>
<li>When ready, click <strong>"Resume"</strong></li>
<li>Job returns to pending queue</li>
</ol>
<hr />
<h2 id="job-type-details">Job Type Details<a class="headerlink" href="#job-type-details" title="Permanent link">&para;</a></h2>
<h3 id="scan-jobs-scan-public_scan">Scan Jobs (<code>scan</code>, <code>public_scan</code>)<a class="headerlink" href="#scan-jobs-scan-public_scan" title="Permanent link">&para;</a></h3>
<p><strong>Purpose:</strong> Scan filesystem directory for new videos and create database records</p>
<p><strong>Parameters:</strong></p>
<div class="language-json highlight"><pre><span></span><code><span id="__span-19-1"><a id="__codelineno-19-1" name="__codelineno-19-1" href="#__codelineno-19-1"></a><span class="p">{</span>
</span><span id="__span-19-2"><a id="__codelineno-19-2" name="__codelineno-19-2" href="#__codelineno-19-2"></a><span class="w"> </span><span class="nt">&quot;directoryType&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;videos&quot;</span><span class="p">,</span>
</span><span id="__span-19-3"><a id="__codelineno-19-3" name="__codelineno-19-3" href="#__codelineno-19-3"></a><span class="w"> </span><span class="nt">&quot;skipExisting&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span>
</span><span id="__span-19-4"><a id="__codelineno-19-4" name="__codelineno-19-4" href="#__codelineno-19-4"></a><span class="p">}</span>
</span></code></pre></div>
<p><strong>Process:</strong></p>
<ol>
<li>Read directory <code>/media/local/library/{directoryType}/</code></li>
<li>Filter for video extensions (<code>.mp4</code>, <code>.mov</code>, etc.)</li>
<li>Check each file against database (by path)</li>
<li>Create records for new files</li>
<li>Run FFprobe on new files</li>
<li>Update progress: files processed / total files</li>
</ol>
<p><strong>Typical Duration:</strong> 2-30 seconds (depends on file count)</p>
<hr />
<h3 id="validation-jobs-validate">Validation Jobs (<code>validate</code>)<a class="headerlink" href="#validation-jobs-validate" title="Permanent link">&para;</a></h3>
<p><strong>Purpose:</strong> Re-run FFprobe to refresh video metadata</p>
<p><strong>Parameters:</strong></p>
<div class="language-json highlight"><pre><span></span><code><span id="__span-20-1"><a id="__codelineno-20-1" name="__codelineno-20-1" href="#__codelineno-20-1"></a><span class="p">{</span>
</span><span id="__span-20-2"><a id="__codelineno-20-2" name="__codelineno-20-2" href="#__codelineno-20-2"></a><span class="w"> </span><span class="nt">&quot;videoId&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;660e8400-e29b-41d4-a716-446655440001&quot;</span>
</span><span id="__span-20-3"><a id="__codelineno-20-3" name="__codelineno-20-3" href="#__codelineno-20-3"></a><span class="p">}</span>
</span></code></pre></div>
<p><strong>Process:</strong></p>
<ol>
<li>Fetch video record from database</li>
<li>Build full file path</li>
<li>Run FFprobe extraction</li>
<li>Update database with fresh metadata</li>
<li>Mark video as valid/invalid based on result</li>
</ol>
<p><strong>Typical Duration:</strong> 100-500ms per video</p>
<hr />
<h3 id="re-encode-jobs-reencode_streaming">Re-encode Jobs (<code>reencode_streaming</code>)<a class="headerlink" href="#re-encode-jobs-reencode_streaming" title="Permanent link">&para;</a></h3>
<p><strong>Purpose:</strong> Convert video to web-optimized format (H.264, web-friendly profile)</p>
<p><strong>Parameters:</strong></p>
<div class="language-json highlight"><pre><span></span><code><span id="__span-21-1"><a id="__codelineno-21-1" name="__codelineno-21-1" href="#__codelineno-21-1"></a><span class="p">{</span>
</span><span id="__span-21-2"><a id="__codelineno-21-2" name="__codelineno-21-2" href="#__codelineno-21-2"></a><span class="w"> </span><span class="nt">&quot;videoId&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;660e8400-e29b-41d4-a716-446655440001&quot;</span><span class="p">,</span>
</span><span id="__span-21-3"><a id="__codelineno-21-3" name="__codelineno-21-3" href="#__codelineno-21-3"></a><span class="w"> </span><span class="nt">&quot;targetBitrate&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">2000</span><span class="p">,</span>
</span><span id="__span-21-4"><a id="__codelineno-21-4" name="__codelineno-21-4" href="#__codelineno-21-4"></a><span class="w"> </span><span class="nt">&quot;preset&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;medium&quot;</span><span class="p">,</span>
</span><span id="__span-21-5"><a id="__codelineno-21-5" name="__codelineno-21-5" href="#__codelineno-21-5"></a><span class="w"> </span><span class="nt">&quot;crf&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">23</span>
</span><span id="__span-21-6"><a id="__codelineno-21-6" name="__codelineno-21-6" href="#__codelineno-21-6"></a><span class="p">}</span>
</span></code></pre></div>
<p><strong>FFmpeg Command:</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-22-1"><a id="__codelineno-22-1" name="__codelineno-22-1" href="#__codelineno-22-1"></a>ffmpeg<span class="w"> </span>-i<span class="w"> </span>/media/local/inbox/original.mp4<span class="w"> </span><span class="se">\</span>
</span><span id="__span-22-2"><a id="__codelineno-22-2" name="__codelineno-22-2" href="#__codelineno-22-2"></a><span class="w"> </span>-c:v<span class="w"> </span>libx264<span class="w"> </span><span class="se">\</span>
</span><span id="__span-22-3"><a id="__codelineno-22-3" name="__codelineno-22-3" href="#__codelineno-22-3"></a><span class="w"> </span>-preset<span class="w"> </span>medium<span class="w"> </span><span class="se">\</span>
</span><span id="__span-22-4"><a id="__codelineno-22-4" name="__codelineno-22-4" href="#__codelineno-22-4"></a><span class="w"> </span>-crf<span class="w"> </span><span class="m">23</span><span class="w"> </span><span class="se">\</span>
</span><span id="__span-22-5"><a id="__codelineno-22-5" name="__codelineno-22-5" href="#__codelineno-22-5"></a><span class="w"> </span>-maxrate<span class="w"> </span>2000k<span class="w"> </span><span class="se">\</span>
</span><span id="__span-22-6"><a id="__codelineno-22-6" name="__codelineno-22-6" href="#__codelineno-22-6"></a><span class="w"> </span>-bufsize<span class="w"> </span>4000k<span class="w"> </span><span class="se">\</span>
</span><span id="__span-22-7"><a id="__codelineno-22-7" name="__codelineno-22-7" href="#__codelineno-22-7"></a><span class="w"> </span>-c:a<span class="w"> </span>aac<span class="w"> </span><span class="se">\</span>
</span><span id="__span-22-8"><a id="__codelineno-22-8" name="__codelineno-22-8" href="#__codelineno-22-8"></a><span class="w"> </span>-b:a<span class="w"> </span>128k<span class="w"> </span><span class="se">\</span>
</span><span id="__span-22-9"><a id="__codelineno-22-9" name="__codelineno-22-9" href="#__codelineno-22-9"></a><span class="w"> </span>-movflags<span class="w"> </span>+faststart<span class="w"> </span><span class="se">\</span>
</span><span id="__span-22-10"><a id="__codelineno-22-10" name="__codelineno-22-10" href="#__codelineno-22-10"></a><span class="w"> </span>/media/local/playback/encoded.mp4
</span></code></pre></div>
<p><strong>Process:</strong></p>
<ol>
<li>Validate input file exists</li>
<li>Build FFmpeg command</li>
<li>Start encoding process</li>
<li>Parse FFmpeg progress output</li>
<li>Update job progress every ~5%</li>
<li>Create new video record for encoded file</li>
<li>Update original video <code>reencodeJobId</code> reference</li>
</ol>
<p><strong>Typical Duration:</strong> 5-30 minutes (depends on video length and resolution)</p>
<hr />
<h3 id="compilation-jobs-compile_random-compile_quad-compile_mega">Compilation Jobs (<code>compile_random</code>, <code>compile_quad</code>, <code>compile_mega</code>)<a class="headerlink" href="#compilation-jobs-compile_random-compile_quad-compile_mega" title="Permanent link">&para;</a></h3>
<p><strong>Purpose:</strong> Merge multiple videos into single compilation</p>
<p><strong>Parameters (Random):</strong></p>
<div class="language-json highlight"><pre><span></span><code><span id="__span-23-1"><a id="__codelineno-23-1" name="__codelineno-23-1" href="#__codelineno-23-1"></a><span class="p">{</span>
</span><span id="__span-23-2"><a id="__codelineno-23-2" name="__codelineno-23-2" href="#__codelineno-23-2"></a><span class="w"> </span><span class="nt">&quot;count&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span>
</span><span id="__span-23-3"><a id="__codelineno-23-3" name="__codelineno-23-3" href="#__codelineno-23-3"></a><span class="w"> </span><span class="nt">&quot;minDuration&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">30</span><span class="p">,</span>
</span><span id="__span-23-4"><a id="__codelineno-23-4" name="__codelineno-23-4" href="#__codelineno-23-4"></a><span class="w"> </span><span class="nt">&quot;maxDuration&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">120</span><span class="p">,</span>
</span><span id="__span-23-5"><a id="__codelineno-23-5" name="__codelineno-23-5" href="#__codelineno-23-5"></a><span class="w"> </span><span class="nt">&quot;orientation&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;landscape&quot;</span><span class="p">,</span>
</span><span id="__span-23-6"><a id="__codelineno-23-6" name="__codelineno-23-6" href="#__codelineno-23-6"></a><span class="w"> </span><span class="nt">&quot;outputPath&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;compilations/random-001.mp4&quot;</span>
</span><span id="__span-23-7"><a id="__codelineno-23-7" name="__codelineno-23-7" href="#__codelineno-23-7"></a><span class="p">}</span>
</span></code></pre></div>
<p><strong>Process:</strong></p>
<ol>
<li>Query database for videos matching criteria (orientation, duration range)</li>
<li>Randomly select <code>count</code> videos</li>
<li>Build FFmpeg concat demuxer file list</li>
<li>Run FFmpeg compilation</li>
<li>Create new video record for compilation</li>
<li>Update progress based on FFmpeg output</li>
</ol>
<p><strong>Quad Compilation (4-up grid):</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-24-1"><a id="__codelineno-24-1" name="__codelineno-24-1" href="#__codelineno-24-1"></a>ffmpeg<span class="w"> </span>-i<span class="w"> </span>video1.mp4<span class="w"> </span>-i<span class="w"> </span>video2.mp4<span class="w"> </span>-i<span class="w"> </span>video3.mp4<span class="w"> </span>-i<span class="w"> </span>video4.mp4<span class="w"> </span><span class="se">\</span>
</span><span id="__span-24-2"><a id="__codelineno-24-2" name="__codelineno-24-2" href="#__codelineno-24-2"></a><span class="w"> </span>-filter_complex<span class="w"> </span><span class="s2">&quot;[0:v][1:v][2:v][3:v]xstack=inputs=4:layout=0_0|w0_0|0_h0|w0_h0[v]&quot;</span><span class="w"> </span><span class="se">\</span>
</span><span id="__span-24-3"><a id="__codelineno-24-3" name="__codelineno-24-3" href="#__codelineno-24-3"></a><span class="w"> </span>-map<span class="w"> </span><span class="s2">&quot;[v]&quot;</span><span class="w"> </span><span class="se">\</span>
</span><span id="__span-24-4"><a id="__codelineno-24-4" name="__codelineno-24-4" href="#__codelineno-24-4"></a><span class="w"> </span>output.mp4
</span></code></pre></div>
<p><strong>Typical Duration:</strong> 10-60 minutes</p>
<hr />
<h3 id="digest-generation-digest_generate">Digest Generation (<code>digest_generate</code>)<a class="headerlink" href="#digest-generation-digest_generate" title="Permanent link">&para;</a></h3>
<p><strong>Purpose:</strong> AI-powered video digest creation (future feature)</p>
<p><strong>Parameters:</strong></p>
<div class="language-json highlight"><pre><span></span><code><span id="__span-25-1"><a id="__codelineno-25-1" name="__codelineno-25-1" href="#__codelineno-25-1"></a><span class="p">{</span>
</span><span id="__span-25-2"><a id="__codelineno-25-2" name="__codelineno-25-2" href="#__codelineno-25-2"></a><span class="w"> </span><span class="nt">&quot;videoId&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;660e8400-e29b-41d4-a716-446655440001&quot;</span><span class="p">,</span>
</span><span id="__span-25-3"><a id="__codelineno-25-3" name="__codelineno-25-3" href="#__codelineno-25-3"></a><span class="w"> </span><span class="nt">&quot;targetLength&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">60</span><span class="p">,</span>
</span><span id="__span-25-4"><a id="__codelineno-25-4" name="__codelineno-25-4" href="#__codelineno-25-4"></a><span class="w"> </span><span class="nt">&quot;includeHighlights&quot;</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span>
</span><span id="__span-25-5"><a id="__codelineno-25-5" name="__codelineno-25-5" href="#__codelineno-25-5"></a><span class="p">}</span>
</span></code></pre></div>
<p><strong>Process (Planned):</strong></p>
<ol>
<li>Extract frames at 1 FPS</li>
<li>Run AI scene detection</li>
<li>Identify highlights (action, faces, motion)</li>
<li>Select best segments totaling target length</li>
<li>Compile segments into digest video</li>
</ol>
<p><strong>GPU AI Required:</strong> 8GB VRAM</p>
<hr />
<h3 id="thumbnail-generation-thumbnail_generate">Thumbnail Generation (<code>thumbnail_generate</code>)<a class="headerlink" href="#thumbnail-generation-thumbnail_generate" title="Permanent link">&para;</a></h3>
<p><strong>Purpose:</strong> Extract thumbnail image from video</p>
<p><strong>Parameters:</strong></p>
<div class="language-json highlight"><pre><span></span><code><span id="__span-26-1"><a id="__codelineno-26-1" name="__codelineno-26-1" href="#__codelineno-26-1"></a><span class="p">{</span>
</span><span id="__span-26-2"><a id="__codelineno-26-2" name="__codelineno-26-2" href="#__codelineno-26-2"></a><span class="w"> </span><span class="nt">&quot;videoId&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;660e8400-e29b-41d4-a716-446655440001&quot;</span><span class="p">,</span>
</span><span id="__span-26-3"><a id="__codelineno-26-3" name="__codelineno-26-3" href="#__codelineno-26-3"></a><span class="w"> </span><span class="nt">&quot;timestamp&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">5</span><span class="p">,</span>
</span><span id="__span-26-4"><a id="__codelineno-26-4" name="__codelineno-26-4" href="#__codelineno-26-4"></a><span class="w"> </span><span class="nt">&quot;width&quot;</span><span class="p">:</span><span class="w"> </span><span class="mi">640</span>
</span><span id="__span-26-5"><a id="__codelineno-26-5" name="__codelineno-26-5" href="#__codelineno-26-5"></a><span class="p">}</span>
</span></code></pre></div>
<p><strong>FFmpeg Command:</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-27-1"><a id="__codelineno-27-1" name="__codelineno-27-1" href="#__codelineno-27-1"></a>ffmpeg<span class="w"> </span>-i<span class="w"> </span>/media/local/library/videos/sample.mp4<span class="w"> </span><span class="se">\</span>
</span><span id="__span-27-2"><a id="__codelineno-27-2" name="__codelineno-27-2" href="#__codelineno-27-2"></a><span class="w"> </span>-ss<span class="w"> </span><span class="m">00</span>:00:05<span class="w"> </span><span class="se">\</span>
</span><span id="__span-27-3"><a id="__codelineno-27-3" name="__codelineno-27-3" href="#__codelineno-27-3"></a><span class="w"> </span>-vframes<span class="w"> </span><span class="m">1</span><span class="w"> </span><span class="se">\</span>
</span><span id="__span-27-4"><a id="__codelineno-27-4" name="__codelineno-27-4" href="#__codelineno-27-4"></a><span class="w"> </span>-vf<span class="w"> </span><span class="nv">scale</span><span class="o">=</span><span class="m">640</span>:-1<span class="w"> </span><span class="se">\</span>
</span><span id="__span-27-5"><a id="__codelineno-27-5" name="__codelineno-27-5" href="#__codelineno-27-5"></a><span class="w"> </span>/media/local/thumbnails/sample.jpg
</span></code></pre></div>
<p><strong>Process:</strong></p>
<ol>
<li>Seek to timestamp (default: 25% into video)</li>
<li>Extract single frame</li>
<li>Scale to width (preserve aspect ratio)</li>
<li>Save as JPEG</li>
<li>Update video record with <code>thumbnailPath</code></li>
</ol>
<p><strong>Typical Duration:</strong> 1-5 seconds</p>
<hr />
<h2 id="code-examples">Code Examples<a class="headerlink" href="#code-examples" title="Permanent link">&para;</a></h2>
<h3 id="create-re-encode-job">Create Re-encode Job<a class="headerlink" href="#create-re-encode-job" title="Permanent link">&para;</a></h3>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-28-1"><a id="__codelineno-28-1" name="__codelineno-28-1" href="#__codelineno-28-1"></a><span class="c1">// api/src/modules/media/routes/jobs.routes.ts</span>
</span><span id="__span-28-2"><a id="__codelineno-28-2" name="__codelineno-28-2" href="#__codelineno-28-2"></a><span class="k">import</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">db</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="kr">from</span><span class="w"> </span><span class="s1">&#39;@/modules/media/db&#39;</span><span class="p">;</span>
</span><span id="__span-28-3"><a id="__codelineno-28-3" name="__codelineno-28-3" href="#__codelineno-28-3"></a><span class="k">import</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">jobs</span><span class="p">,</span><span class="w"> </span><span class="nx">videos</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="kr">from</span><span class="w"> </span><span class="s1">&#39;@/modules/media/db/schema&#39;</span><span class="p">;</span>
</span><span id="__span-28-4"><a id="__codelineno-28-4" name="__codelineno-28-4" href="#__codelineno-28-4"></a>
</span><span id="__span-28-5"><a id="__codelineno-28-5" name="__codelineno-28-5" href="#__codelineno-28-5"></a><span class="nx">app</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s1">&#39;/api/media/jobs/reencode&#39;</span><span class="p">,</span><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="p">(</span><span class="nx">req</span><span class="p">,</span><span class="w"> </span><span class="nx">reply</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-28-6"><a id="__codelineno-28-6" name="__codelineno-28-6" href="#__codelineno-28-6"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">videoId</span><span class="p">,</span><span class="w"> </span><span class="nx">targetBitrate</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">2000</span><span class="p">,</span><span class="w"> </span><span class="nx">preset</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;medium&#39;</span><span class="p">,</span><span class="w"> </span><span class="nx">crf</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">23</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">;</span>
</span><span id="__span-28-7"><a id="__codelineno-28-7" name="__codelineno-28-7" href="#__codelineno-28-7"></a>
</span><span id="__span-28-8"><a id="__codelineno-28-8" name="__codelineno-28-8" href="#__codelineno-28-8"></a><span class="w"> </span><span class="c1">// Fetch video</span>
</span><span id="__span-28-9"><a id="__codelineno-28-9" name="__codelineno-28-9" href="#__codelineno-28-9"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="p">[</span><span class="nx">video</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">db</span>
</span><span id="__span-28-10"><a id="__codelineno-28-10" name="__codelineno-28-10" href="#__codelineno-28-10"></a><span class="w"> </span><span class="p">.</span><span class="nx">select</span><span class="p">()</span>
</span><span id="__span-28-11"><a id="__codelineno-28-11" name="__codelineno-28-11" href="#__codelineno-28-11"></a><span class="w"> </span><span class="p">.</span><span class="kr">from</span><span class="p">(</span><span class="nx">videos</span><span class="p">)</span>
</span><span id="__span-28-12"><a id="__codelineno-28-12" name="__codelineno-28-12" href="#__codelineno-28-12"></a><span class="w"> </span><span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="nx">eq</span><span class="p">(</span><span class="nx">videos</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="nx">videoId</span><span class="p">))</span>
</span><span id="__span-28-13"><a id="__codelineno-28-13" name="__codelineno-28-13" href="#__codelineno-28-13"></a><span class="w"> </span><span class="p">.</span><span class="nx">limit</span><span class="p">(</span><span class="mf">1</span><span class="p">);</span>
</span><span id="__span-28-14"><a id="__codelineno-28-14" name="__codelineno-28-14" href="#__codelineno-28-14"></a>
</span><span id="__span-28-15"><a id="__codelineno-28-15" name="__codelineno-28-15" href="#__codelineno-28-15"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="nx">video</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-28-16"><a id="__codelineno-28-16" name="__codelineno-28-16" href="#__codelineno-28-16"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">reply</span><span class="p">.</span><span class="nx">code</span><span class="p">(</span><span class="mf">404</span><span class="p">).</span><span class="nx">send</span><span class="p">({</span><span class="w"> </span><span class="nx">error</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;Video not found&#39;</span><span class="w"> </span><span class="p">});</span>
</span><span id="__span-28-17"><a id="__codelineno-28-17" name="__codelineno-28-17" href="#__codelineno-28-17"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-28-18"><a id="__codelineno-28-18" name="__codelineno-28-18" href="#__codelineno-28-18"></a>
</span><span id="__span-28-19"><a id="__codelineno-28-19" name="__codelineno-28-19" href="#__codelineno-28-19"></a><span class="w"> </span><span class="c1">// Create job</span>
</span><span id="__span-28-20"><a id="__codelineno-28-20" name="__codelineno-28-20" href="#__codelineno-28-20"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="p">[</span><span class="nx">job</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">db</span>
</span><span id="__span-28-21"><a id="__codelineno-28-21" name="__codelineno-28-21" href="#__codelineno-28-21"></a><span class="w"> </span><span class="p">.</span><span class="nx">insert</span><span class="p">(</span><span class="nx">jobs</span><span class="p">)</span>
</span><span id="__span-28-22"><a id="__codelineno-28-22" name="__codelineno-28-22" href="#__codelineno-28-22"></a><span class="w"> </span><span class="p">.</span><span class="nx">values</span><span class="p">({</span>
</span><span id="__span-28-23"><a id="__codelineno-28-23" name="__codelineno-28-23" href="#__codelineno-28-23"></a><span class="w"> </span><span class="kr">type</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;reencode_streaming&#39;</span><span class="p">,</span>
</span><span id="__span-28-24"><a id="__codelineno-28-24" name="__codelineno-28-24" href="#__codelineno-28-24"></a><span class="w"> </span><span class="nx">status</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;pending&#39;</span><span class="p">,</span>
</span><span id="__span-28-25"><a id="__codelineno-28-25" name="__codelineno-28-25" href="#__codelineno-28-25"></a><span class="w"> </span><span class="nx">params</span><span class="o">:</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-28-26"><a id="__codelineno-28-26" name="__codelineno-28-26" href="#__codelineno-28-26"></a><span class="w"> </span><span class="nx">videoId</span><span class="p">,</span>
</span><span id="__span-28-27"><a id="__codelineno-28-27" name="__codelineno-28-27" href="#__codelineno-28-27"></a><span class="w"> </span><span class="nx">inputPath</span><span class="o">:</span><span class="w"> </span><span class="kt">video.path</span><span class="p">,</span>
</span><span id="__span-28-28"><a id="__codelineno-28-28" name="__codelineno-28-28" href="#__codelineno-28-28"></a><span class="w"> </span><span class="nx">outputPath</span><span class="o">:</span><span class="w"> </span><span class="sb">`playback/</span><span class="si">${</span><span class="nx">video</span><span class="p">.</span><span class="nx">filename</span><span class="si">}</span><span class="sb">`</span><span class="p">,</span>
</span><span id="__span-28-29"><a id="__codelineno-28-29" name="__codelineno-28-29" href="#__codelineno-28-29"></a><span class="w"> </span><span class="nx">targetBitrate</span><span class="p">,</span>
</span><span id="__span-28-30"><a id="__codelineno-28-30" name="__codelineno-28-30" href="#__codelineno-28-30"></a><span class="w"> </span><span class="nx">preset</span><span class="p">,</span>
</span><span id="__span-28-31"><a id="__codelineno-28-31" name="__codelineno-28-31" href="#__codelineno-28-31"></a><span class="w"> </span><span class="nx">crf</span><span class="p">,</span>
</span><span id="__span-28-32"><a id="__codelineno-28-32" name="__codelineno-28-32" href="#__codelineno-28-32"></a><span class="w"> </span><span class="p">},</span>
</span><span id="__span-28-33"><a id="__codelineno-28-33" name="__codelineno-28-33" href="#__codelineno-28-33"></a><span class="w"> </span><span class="nx">resourceCategory</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;gpu_encode&#39;</span><span class="p">,</span>
</span><span id="__span-28-34"><a id="__codelineno-28-34" name="__codelineno-28-34" href="#__codelineno-28-34"></a><span class="w"> </span><span class="nx">vramRequired</span><span class="o">:</span><span class="w"> </span><span class="kt">4000</span><span class="p">,</span>
</span><span id="__span-28-35"><a id="__codelineno-28-35" name="__codelineno-28-35" href="#__codelineno-28-35"></a><span class="w"> </span><span class="nx">priority</span><span class="o">:</span><span class="w"> </span><span class="kt">5</span><span class="p">,</span>
</span><span id="__span-28-36"><a id="__codelineno-28-36" name="__codelineno-28-36" href="#__codelineno-28-36"></a><span class="w"> </span><span class="p">})</span>
</span><span id="__span-28-37"><a id="__codelineno-28-37" name="__codelineno-28-37" href="#__codelineno-28-37"></a><span class="w"> </span><span class="p">.</span><span class="nx">returning</span><span class="p">();</span>
</span><span id="__span-28-38"><a id="__codelineno-28-38" name="__codelineno-28-38" href="#__codelineno-28-38"></a>
</span><span id="__span-28-39"><a id="__codelineno-28-39" name="__codelineno-28-39" href="#__codelineno-28-39"></a><span class="w"> </span><span class="nx">reply</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">job</span><span class="p">);</span>
</span><span id="__span-28-40"><a id="__codelineno-28-40" name="__codelineno-28-40" href="#__codelineno-28-40"></a><span class="p">});</span>
</span></code></pre></div>
<hr />
<h3 id="job-worker-polling-loop">Job Worker (Polling Loop)<a class="headerlink" href="#job-worker-polling-loop" title="Permanent link">&para;</a></h3>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-29-1"><a id="__codelineno-29-1" name="__codelineno-29-1" href="#__codelineno-29-1"></a><span class="c1">// api/src/modules/media/services/job-worker.service.ts</span>
</span><span id="__span-29-2"><a id="__codelineno-29-2" name="__codelineno-29-2" href="#__codelineno-29-2"></a><span class="k">import</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">db</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="kr">from</span><span class="w"> </span><span class="s1">&#39;@/modules/media/db&#39;</span><span class="p">;</span>
</span><span id="__span-29-3"><a id="__codelineno-29-3" name="__codelineno-29-3" href="#__codelineno-29-3"></a><span class="k">import</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">jobs</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="kr">from</span><span class="w"> </span><span class="s1">&#39;@/modules/media/db/schema&#39;</span><span class="p">;</span>
</span><span id="__span-29-4"><a id="__codelineno-29-4" name="__codelineno-29-4" href="#__codelineno-29-4"></a><span class="k">import</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">eq</span><span class="p">,</span><span class="w"> </span><span class="nx">and</span><span class="p">,</span><span class="w"> </span><span class="nx">lte</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="kr">from</span><span class="w"> </span><span class="s1">&#39;drizzle-orm&#39;</span><span class="p">;</span>
</span><span id="__span-29-5"><a id="__codelineno-29-5" name="__codelineno-29-5" href="#__codelineno-29-5"></a>
</span><span id="__span-29-6"><a id="__codelineno-29-6" name="__codelineno-29-6" href="#__codelineno-29-6"></a><span class="k">export</span><span class="w"> </span><span class="kd">class</span><span class="w"> </span><span class="nx">JobWorkerService</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-7"><a id="__codelineno-29-7" name="__codelineno-29-7" href="#__codelineno-29-7"></a><span class="w"> </span><span class="k">private</span><span class="w"> </span><span class="nx">polling</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">false</span><span class="p">;</span>
</span><span id="__span-29-8"><a id="__codelineno-29-8" name="__codelineno-29-8" href="#__codelineno-29-8"></a>
</span><span id="__span-29-9"><a id="__codelineno-29-9" name="__codelineno-29-9" href="#__codelineno-29-9"></a><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="nx">start</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-10"><a id="__codelineno-29-10" name="__codelineno-29-10" href="#__codelineno-29-10"></a><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">polling</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">true</span><span class="p">;</span>
</span><span id="__span-29-11"><a id="__codelineno-29-11" name="__codelineno-29-11" href="#__codelineno-29-11"></a><span class="w"> </span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Job worker started&#39;</span><span class="p">);</span>
</span><span id="__span-29-12"><a id="__codelineno-29-12" name="__codelineno-29-12" href="#__codelineno-29-12"></a>
</span><span id="__span-29-13"><a id="__codelineno-29-13" name="__codelineno-29-13" href="#__codelineno-29-13"></a><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">polling</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-14"><a id="__codelineno-29-14" name="__codelineno-29-14" href="#__codelineno-29-14"></a><span class="w"> </span><span class="k">try</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-15"><a id="__codelineno-29-15" name="__codelineno-29-15" href="#__codelineno-29-15"></a><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">processNextJob</span><span class="p">();</span>
</span><span id="__span-29-16"><a id="__codelineno-29-16" name="__codelineno-29-16" href="#__codelineno-29-16"></a><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">catch</span><span class="w"> </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-17"><a id="__codelineno-29-17" name="__codelineno-29-17" href="#__codelineno-29-17"></a><span class="w"> </span><span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s1">&#39;Job worker error:&#39;</span><span class="p">,</span><span class="w"> </span><span class="nx">error</span><span class="p">);</span>
</span><span id="__span-29-18"><a id="__codelineno-29-18" name="__codelineno-29-18" href="#__codelineno-29-18"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-29-19"><a id="__codelineno-29-19" name="__codelineno-29-19" href="#__codelineno-29-19"></a>
</span><span id="__span-29-20"><a id="__codelineno-29-20" name="__codelineno-29-20" href="#__codelineno-29-20"></a><span class="w"> </span><span class="c1">// Wait 5 seconds before next poll</span>
</span><span id="__span-29-21"><a id="__codelineno-29-21" name="__codelineno-29-21" href="#__codelineno-29-21"></a><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nb">Promise</span><span class="p">((</span><span class="nx">resolve</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="nx">setTimeout</span><span class="p">(</span><span class="nx">resolve</span><span class="p">,</span><span class="w"> </span><span class="mf">5000</span><span class="p">));</span>
</span><span id="__span-29-22"><a id="__codelineno-29-22" name="__codelineno-29-22" href="#__codelineno-29-22"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-29-23"><a id="__codelineno-29-23" name="__codelineno-29-23" href="#__codelineno-29-23"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-29-24"><a id="__codelineno-29-24" name="__codelineno-29-24" href="#__codelineno-29-24"></a>
</span><span id="__span-29-25"><a id="__codelineno-29-25" name="__codelineno-29-25" href="#__codelineno-29-25"></a><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="nx">stop</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-26"><a id="__codelineno-29-26" name="__codelineno-29-26" href="#__codelineno-29-26"></a><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">polling</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">false</span><span class="p">;</span>
</span><span id="__span-29-27"><a id="__codelineno-29-27" name="__codelineno-29-27" href="#__codelineno-29-27"></a><span class="w"> </span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Job worker stopped&#39;</span><span class="p">);</span>
</span><span id="__span-29-28"><a id="__codelineno-29-28" name="__codelineno-29-28" href="#__codelineno-29-28"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-29-29"><a id="__codelineno-29-29" name="__codelineno-29-29" href="#__codelineno-29-29"></a>
</span><span id="__span-29-30"><a id="__codelineno-29-30" name="__codelineno-29-30" href="#__codelineno-29-30"></a><span class="w"> </span><span class="k">private</span><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="nx">processNextJob</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-31"><a id="__codelineno-29-31" name="__codelineno-29-31" href="#__codelineno-29-31"></a><span class="w"> </span><span class="c1">// Find next pending job (highest priority first)</span>
</span><span id="__span-29-32"><a id="__codelineno-29-32" name="__codelineno-29-32" href="#__codelineno-29-32"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="p">[</span><span class="nx">job</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">db</span>
</span><span id="__span-29-33"><a id="__codelineno-29-33" name="__codelineno-29-33" href="#__codelineno-29-33"></a><span class="w"> </span><span class="p">.</span><span class="nx">select</span><span class="p">()</span>
</span><span id="__span-29-34"><a id="__codelineno-29-34" name="__codelineno-29-34" href="#__codelineno-29-34"></a><span class="w"> </span><span class="p">.</span><span class="kr">from</span><span class="p">(</span><span class="nx">jobs</span><span class="p">)</span>
</span><span id="__span-29-35"><a id="__codelineno-29-35" name="__codelineno-29-35" href="#__codelineno-29-35"></a><span class="w"> </span><span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="nx">eq</span><span class="p">(</span><span class="nx">jobs</span><span class="p">.</span><span class="nx">status</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;pending&#39;</span><span class="p">))</span>
</span><span id="__span-29-36"><a id="__codelineno-29-36" name="__codelineno-29-36" href="#__codelineno-29-36"></a><span class="w"> </span><span class="p">.</span><span class="nx">orderBy</span><span class="p">(</span><span class="nx">jobs</span><span class="p">.</span><span class="nx">priority</span><span class="p">,</span><span class="w"> </span><span class="nx">jobs</span><span class="p">.</span><span class="nx">createdAt</span><span class="p">)</span>
</span><span id="__span-29-37"><a id="__codelineno-29-37" name="__codelineno-29-37" href="#__codelineno-29-37"></a><span class="w"> </span><span class="p">.</span><span class="nx">limit</span><span class="p">(</span><span class="mf">1</span><span class="p">);</span>
</span><span id="__span-29-38"><a id="__codelineno-29-38" name="__codelineno-29-38" href="#__codelineno-29-38"></a>
</span><span id="__span-29-39"><a id="__codelineno-29-39" name="__codelineno-29-39" href="#__codelineno-29-39"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="nx">job</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-40"><a id="__codelineno-29-40" name="__codelineno-29-40" href="#__codelineno-29-40"></a><span class="w"> </span><span class="k">return</span><span class="p">;</span><span class="w"> </span><span class="c1">// No jobs in queue</span>
</span><span id="__span-29-41"><a id="__codelineno-29-41" name="__codelineno-29-41" href="#__codelineno-29-41"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-29-42"><a id="__codelineno-29-42" name="__codelineno-29-42" href="#__codelineno-29-42"></a>
</span><span id="__span-29-43"><a id="__codelineno-29-43" name="__codelineno-29-43" href="#__codelineno-29-43"></a><span class="w"> </span><span class="c1">// Check resource availability</span>
</span><span id="__span-29-44"><a id="__codelineno-29-44" name="__codelineno-29-44" href="#__codelineno-29-44"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">canRun</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">checkResources</span><span class="p">(</span><span class="nx">job</span><span class="p">);</span>
</span><span id="__span-29-45"><a id="__codelineno-29-45" name="__codelineno-29-45" href="#__codelineno-29-45"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="nx">canRun</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-46"><a id="__codelineno-29-46" name="__codelineno-29-46" href="#__codelineno-29-46"></a><span class="w"> </span><span class="c1">// Update waiting reason</span>
</span><span id="__span-29-47"><a id="__codelineno-29-47" name="__codelineno-29-47" href="#__codelineno-29-47"></a><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">db</span>
</span><span id="__span-29-48"><a id="__codelineno-29-48" name="__codelineno-29-48" href="#__codelineno-29-48"></a><span class="w"> </span><span class="p">.</span><span class="nx">update</span><span class="p">(</span><span class="nx">jobs</span><span class="p">)</span>
</span><span id="__span-29-49"><a id="__codelineno-29-49" name="__codelineno-29-49" href="#__codelineno-29-49"></a><span class="w"> </span><span class="p">.</span><span class="nx">set</span><span class="p">({</span><span class="w"> </span><span class="nx">waitingReason</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;Insufficient resources&#39;</span><span class="w"> </span><span class="p">})</span>
</span><span id="__span-29-50"><a id="__codelineno-29-50" name="__codelineno-29-50" href="#__codelineno-29-50"></a><span class="w"> </span><span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="nx">eq</span><span class="p">(</span><span class="nx">jobs</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="nx">job</span><span class="p">.</span><span class="nx">id</span><span class="p">));</span>
</span><span id="__span-29-51"><a id="__codelineno-29-51" name="__codelineno-29-51" href="#__codelineno-29-51"></a><span class="w"> </span><span class="k">return</span><span class="p">;</span>
</span><span id="__span-29-52"><a id="__codelineno-29-52" name="__codelineno-29-52" href="#__codelineno-29-52"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-29-53"><a id="__codelineno-29-53" name="__codelineno-29-53" href="#__codelineno-29-53"></a>
</span><span id="__span-29-54"><a id="__codelineno-29-54" name="__codelineno-29-54" href="#__codelineno-29-54"></a><span class="w"> </span><span class="c1">// Start job</span>
</span><span id="__span-29-55"><a id="__codelineno-29-55" name="__codelineno-29-55" href="#__codelineno-29-55"></a><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">executeJob</span><span class="p">(</span><span class="nx">job</span><span class="p">);</span>
</span><span id="__span-29-56"><a id="__codelineno-29-56" name="__codelineno-29-56" href="#__codelineno-29-56"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-29-57"><a id="__codelineno-29-57" name="__codelineno-29-57" href="#__codelineno-29-57"></a>
</span><span id="__span-29-58"><a id="__codelineno-29-58" name="__codelineno-29-58" href="#__codelineno-29-58"></a><span class="w"> </span><span class="k">private</span><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="nx">checkResources</span><span class="p">(</span><span class="nx">job</span><span class="o">:</span><span class="w"> </span><span class="kt">any</span><span class="p">)</span><span class="o">:</span><span class="w"> </span><span class="nb">Promise</span><span class="o">&lt;</span><span class="kt">boolean</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-59"><a id="__codelineno-29-59" name="__codelineno-29-59" href="#__codelineno-29-59"></a><span class="w"> </span><span class="c1">// Get running jobs</span>
</span><span id="__span-29-60"><a id="__codelineno-29-60" name="__codelineno-29-60" href="#__codelineno-29-60"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">runningJobs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">db</span>
</span><span id="__span-29-61"><a id="__codelineno-29-61" name="__codelineno-29-61" href="#__codelineno-29-61"></a><span class="w"> </span><span class="p">.</span><span class="nx">select</span><span class="p">()</span>
</span><span id="__span-29-62"><a id="__codelineno-29-62" name="__codelineno-29-62" href="#__codelineno-29-62"></a><span class="w"> </span><span class="p">.</span><span class="kr">from</span><span class="p">(</span><span class="nx">jobs</span><span class="p">)</span>
</span><span id="__span-29-63"><a id="__codelineno-29-63" name="__codelineno-29-63" href="#__codelineno-29-63"></a><span class="w"> </span><span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="nx">eq</span><span class="p">(</span><span class="nx">jobs</span><span class="p">.</span><span class="nx">status</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;running&#39;</span><span class="p">));</span>
</span><span id="__span-29-64"><a id="__codelineno-29-64" name="__codelineno-29-64" href="#__codelineno-29-64"></a>
</span><span id="__span-29-65"><a id="__codelineno-29-65" name="__codelineno-29-65" href="#__codelineno-29-65"></a><span class="w"> </span><span class="c1">// Calculate total VRAM used</span>
</span><span id="__span-29-66"><a id="__codelineno-29-66" name="__codelineno-29-66" href="#__codelineno-29-66"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">totalVramUsed</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">runningJobs</span><span class="p">.</span><span class="nx">reduce</span><span class="p">(</span>
</span><span id="__span-29-67"><a id="__codelineno-29-67" name="__codelineno-29-67" href="#__codelineno-29-67"></a><span class="w"> </span><span class="p">(</span><span class="nx">sum</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="nx">sum</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="nx">j</span><span class="p">.</span><span class="nx">vramRequired</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="mf">0</span><span class="p">),</span>
</span><span id="__span-29-68"><a id="__codelineno-29-68" name="__codelineno-29-68" href="#__codelineno-29-68"></a><span class="w"> </span><span class="mf">0</span>
</span><span id="__span-29-69"><a id="__codelineno-29-69" name="__codelineno-29-69" href="#__codelineno-29-69"></a><span class="w"> </span><span class="p">);</span>
</span><span id="__span-29-70"><a id="__codelineno-29-70" name="__codelineno-29-70" href="#__codelineno-29-70"></a>
</span><span id="__span-29-71"><a id="__codelineno-29-71" name="__codelineno-29-71" href="#__codelineno-29-71"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">TOTAL_VRAM</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">16000</span><span class="p">;</span><span class="w"> </span><span class="c1">// 16GB GPU</span>
</span><span id="__span-29-72"><a id="__codelineno-29-72" name="__codelineno-29-72" href="#__codelineno-29-72"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">available</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">TOTAL_VRAM</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="nx">totalVramUsed</span><span class="p">;</span>
</span><span id="__span-29-73"><a id="__codelineno-29-73" name="__codelineno-29-73" href="#__codelineno-29-73"></a>
</span><span id="__span-29-74"><a id="__codelineno-29-74" name="__codelineno-29-74" href="#__codelineno-29-74"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">job</span><span class="p">.</span><span class="nx">vramRequired</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">job</span><span class="p">.</span><span class="nx">vramRequired</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="nx">available</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-75"><a id="__codelineno-29-75" name="__codelineno-29-75" href="#__codelineno-29-75"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">false</span><span class="p">;</span><span class="w"> </span><span class="c1">// Not enough VRAM</span>
</span><span id="__span-29-76"><a id="__codelineno-29-76" name="__codelineno-29-76" href="#__codelineno-29-76"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-29-77"><a id="__codelineno-29-77" name="__codelineno-29-77" href="#__codelineno-29-77"></a>
</span><span id="__span-29-78"><a id="__codelineno-29-78" name="__codelineno-29-78" href="#__codelineno-29-78"></a><span class="w"> </span><span class="c1">// Check concurrent job limits by category</span>
</span><span id="__span-29-79"><a id="__codelineno-29-79" name="__codelineno-29-79" href="#__codelineno-29-79"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">categoryCount</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">runningJobs</span><span class="p">.</span><span class="nx">filter</span><span class="p">(</span>
</span><span id="__span-29-80"><a id="__codelineno-29-80" name="__codelineno-29-80" href="#__codelineno-29-80"></a><span class="w"> </span><span class="p">(</span><span class="nx">j</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="nx">j</span><span class="p">.</span><span class="nx">resourceCategory</span><span class="w"> </span><span class="o">===</span><span class="w"> </span><span class="nx">job</span><span class="p">.</span><span class="nx">resourceCategory</span>
</span><span id="__span-29-81"><a id="__codelineno-29-81" name="__codelineno-29-81" href="#__codelineno-29-81"></a><span class="w"> </span><span class="p">).</span><span class="nx">length</span><span class="p">;</span>
</span><span id="__span-29-82"><a id="__codelineno-29-82" name="__codelineno-29-82" href="#__codelineno-29-82"></a>
</span><span id="__span-29-83"><a id="__codelineno-29-83" name="__codelineno-29-83" href="#__codelineno-29-83"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">limits</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-84"><a id="__codelineno-29-84" name="__codelineno-29-84" href="#__codelineno-29-84"></a><span class="w"> </span><span class="nx">cpu</span><span class="o">:</span><span class="w"> </span><span class="kt">5</span><span class="p">,</span>
</span><span id="__span-29-85"><a id="__codelineno-29-85" name="__codelineno-29-85" href="#__codelineno-29-85"></a><span class="w"> </span><span class="nx">gpu_encode</span><span class="o">:</span><span class="w"> </span><span class="kt">2</span><span class="p">,</span>
</span><span id="__span-29-86"><a id="__codelineno-29-86" name="__codelineno-29-86" href="#__codelineno-29-86"></a><span class="w"> </span><span class="nx">gpu_ai</span><span class="o">:</span><span class="w"> </span><span class="kt">1</span><span class="p">,</span>
</span><span id="__span-29-87"><a id="__codelineno-29-87" name="__codelineno-29-87" href="#__codelineno-29-87"></a><span class="w"> </span><span class="p">};</span>
</span><span id="__span-29-88"><a id="__codelineno-29-88" name="__codelineno-29-88" href="#__codelineno-29-88"></a>
</span><span id="__span-29-89"><a id="__codelineno-29-89" name="__codelineno-29-89" href="#__codelineno-29-89"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">categoryCount</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="nx">limits</span><span class="p">[</span><span class="nx">job</span><span class="p">.</span><span class="nx">resourceCategory</span><span class="w"> </span><span class="kr">as</span><span class="w"> </span><span class="nx">keyof</span><span class="w"> </span><span class="ow">typeof</span><span class="w"> </span><span class="nx">limits</span><span class="p">])</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-90"><a id="__codelineno-29-90" name="__codelineno-29-90" href="#__codelineno-29-90"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">false</span><span class="p">;</span><span class="w"> </span><span class="c1">// Category limit reached</span>
</span><span id="__span-29-91"><a id="__codelineno-29-91" name="__codelineno-29-91" href="#__codelineno-29-91"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-29-92"><a id="__codelineno-29-92" name="__codelineno-29-92" href="#__codelineno-29-92"></a>
</span><span id="__span-29-93"><a id="__codelineno-29-93" name="__codelineno-29-93" href="#__codelineno-29-93"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">true</span><span class="p">;</span><span class="w"> </span><span class="c1">// Resources available</span>
</span><span id="__span-29-94"><a id="__codelineno-29-94" name="__codelineno-29-94" href="#__codelineno-29-94"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-29-95"><a id="__codelineno-29-95" name="__codelineno-29-95" href="#__codelineno-29-95"></a>
</span><span id="__span-29-96"><a id="__codelineno-29-96" name="__codelineno-29-96" href="#__codelineno-29-96"></a><span class="w"> </span><span class="k">private</span><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="nx">executeJob</span><span class="p">(</span><span class="nx">job</span><span class="o">:</span><span class="w"> </span><span class="kt">any</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-97"><a id="__codelineno-29-97" name="__codelineno-29-97" href="#__codelineno-29-97"></a><span class="w"> </span><span class="c1">// Mark as running</span>
</span><span id="__span-29-98"><a id="__codelineno-29-98" name="__codelineno-29-98" href="#__codelineno-29-98"></a><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">db</span>
</span><span id="__span-29-99"><a id="__codelineno-29-99" name="__codelineno-29-99" href="#__codelineno-29-99"></a><span class="w"> </span><span class="p">.</span><span class="nx">update</span><span class="p">(</span><span class="nx">jobs</span><span class="p">)</span>
</span><span id="__span-29-100"><a id="__codelineno-29-100" name="__codelineno-29-100" href="#__codelineno-29-100"></a><span class="w"> </span><span class="p">.</span><span class="nx">set</span><span class="p">({</span>
</span><span id="__span-29-101"><a id="__codelineno-29-101" name="__codelineno-29-101" href="#__codelineno-29-101"></a><span class="w"> </span><span class="nx">status</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;running&#39;</span><span class="p">,</span>
</span><span id="__span-29-102"><a id="__codelineno-29-102" name="__codelineno-29-102" href="#__codelineno-29-102"></a><span class="w"> </span><span class="nx">startedAt</span><span class="o">:</span><span class="w"> </span><span class="kt">new</span><span class="w"> </span><span class="nb">Date</span><span class="p">(),</span>
</span><span id="__span-29-103"><a id="__codelineno-29-103" name="__codelineno-29-103" href="#__codelineno-29-103"></a><span class="w"> </span><span class="nx">waitingReason</span><span class="o">:</span><span class="w"> </span><span class="kt">null</span><span class="p">,</span>
</span><span id="__span-29-104"><a id="__codelineno-29-104" name="__codelineno-29-104" href="#__codelineno-29-104"></a><span class="w"> </span><span class="p">})</span>
</span><span id="__span-29-105"><a id="__codelineno-29-105" name="__codelineno-29-105" href="#__codelineno-29-105"></a><span class="w"> </span><span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="nx">eq</span><span class="p">(</span><span class="nx">jobs</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="nx">job</span><span class="p">.</span><span class="nx">id</span><span class="p">));</span>
</span><span id="__span-29-106"><a id="__codelineno-29-106" name="__codelineno-29-106" href="#__codelineno-29-106"></a>
</span><span id="__span-29-107"><a id="__codelineno-29-107" name="__codelineno-29-107" href="#__codelineno-29-107"></a><span class="w"> </span><span class="k">try</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-108"><a id="__codelineno-29-108" name="__codelineno-29-108" href="#__codelineno-29-108"></a><span class="w"> </span><span class="c1">// Execute job based on type</span>
</span><span id="__span-29-109"><a id="__codelineno-29-109" name="__codelineno-29-109" href="#__codelineno-29-109"></a><span class="w"> </span><span class="k">switch</span><span class="w"> </span><span class="p">(</span><span class="nx">job</span><span class="p">.</span><span class="kr">type</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-110"><a id="__codelineno-29-110" name="__codelineno-29-110" href="#__codelineno-29-110"></a><span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="s1">&#39;reencode_streaming&#39;</span><span class="o">:</span>
</span><span id="__span-29-111"><a id="__codelineno-29-111" name="__codelineno-29-111" href="#__codelineno-29-111"></a><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">executeReencode</span><span class="p">(</span><span class="nx">job</span><span class="p">);</span>
</span><span id="__span-29-112"><a id="__codelineno-29-112" name="__codelineno-29-112" href="#__codelineno-29-112"></a><span class="w"> </span><span class="k">break</span><span class="p">;</span>
</span><span id="__span-29-113"><a id="__codelineno-29-113" name="__codelineno-29-113" href="#__codelineno-29-113"></a><span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="s1">&#39;scan&#39;</span><span class="o">:</span>
</span><span id="__span-29-114"><a id="__codelineno-29-114" name="__codelineno-29-114" href="#__codelineno-29-114"></a><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">executeScan</span><span class="p">(</span><span class="nx">job</span><span class="p">);</span>
</span><span id="__span-29-115"><a id="__codelineno-29-115" name="__codelineno-29-115" href="#__codelineno-29-115"></a><span class="w"> </span><span class="k">break</span><span class="p">;</span>
</span><span id="__span-29-116"><a id="__codelineno-29-116" name="__codelineno-29-116" href="#__codelineno-29-116"></a><span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="s1">&#39;thumbnail_generate&#39;</span><span class="o">:</span>
</span><span id="__span-29-117"><a id="__codelineno-29-117" name="__codelineno-29-117" href="#__codelineno-29-117"></a><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">executeThumbnail</span><span class="p">(</span><span class="nx">job</span><span class="p">);</span>
</span><span id="__span-29-118"><a id="__codelineno-29-118" name="__codelineno-29-118" href="#__codelineno-29-118"></a><span class="w"> </span><span class="k">break</span><span class="p">;</span>
</span><span id="__span-29-119"><a id="__codelineno-29-119" name="__codelineno-29-119" href="#__codelineno-29-119"></a><span class="w"> </span><span class="c1">// ... other job types</span>
</span><span id="__span-29-120"><a id="__codelineno-29-120" name="__codelineno-29-120" href="#__codelineno-29-120"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-29-121"><a id="__codelineno-29-121" name="__codelineno-29-121" href="#__codelineno-29-121"></a>
</span><span id="__span-29-122"><a id="__codelineno-29-122" name="__codelineno-29-122" href="#__codelineno-29-122"></a><span class="w"> </span><span class="c1">// Mark as completed</span>
</span><span id="__span-29-123"><a id="__codelineno-29-123" name="__codelineno-29-123" href="#__codelineno-29-123"></a><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">db</span>
</span><span id="__span-29-124"><a id="__codelineno-29-124" name="__codelineno-29-124" href="#__codelineno-29-124"></a><span class="w"> </span><span class="p">.</span><span class="nx">update</span><span class="p">(</span><span class="nx">jobs</span><span class="p">)</span>
</span><span id="__span-29-125"><a id="__codelineno-29-125" name="__codelineno-29-125" href="#__codelineno-29-125"></a><span class="w"> </span><span class="p">.</span><span class="nx">set</span><span class="p">({</span>
</span><span id="__span-29-126"><a id="__codelineno-29-126" name="__codelineno-29-126" href="#__codelineno-29-126"></a><span class="w"> </span><span class="nx">status</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;completed&#39;</span><span class="p">,</span>
</span><span id="__span-29-127"><a id="__codelineno-29-127" name="__codelineno-29-127" href="#__codelineno-29-127"></a><span class="w"> </span><span class="nx">progress</span><span class="o">:</span><span class="w"> </span><span class="kt">100</span><span class="p">,</span>
</span><span id="__span-29-128"><a id="__codelineno-29-128" name="__codelineno-29-128" href="#__codelineno-29-128"></a><span class="w"> </span><span class="nx">completedAt</span><span class="o">:</span><span class="w"> </span><span class="kt">new</span><span class="w"> </span><span class="nb">Date</span><span class="p">(),</span>
</span><span id="__span-29-129"><a id="__codelineno-29-129" name="__codelineno-29-129" href="#__codelineno-29-129"></a><span class="w"> </span><span class="p">})</span>
</span><span id="__span-29-130"><a id="__codelineno-29-130" name="__codelineno-29-130" href="#__codelineno-29-130"></a><span class="w"> </span><span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="nx">eq</span><span class="p">(</span><span class="nx">jobs</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="nx">job</span><span class="p">.</span><span class="nx">id</span><span class="p">));</span>
</span><span id="__span-29-131"><a id="__codelineno-29-131" name="__codelineno-29-131" href="#__codelineno-29-131"></a><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">catch</span><span class="w"> </span><span class="p">(</span><span class="nx">error</span><span class="o">:</span><span class="w"> </span><span class="kt">any</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-132"><a id="__codelineno-29-132" name="__codelineno-29-132" href="#__codelineno-29-132"></a><span class="w"> </span><span class="c1">// Mark as failed</span>
</span><span id="__span-29-133"><a id="__codelineno-29-133" name="__codelineno-29-133" href="#__codelineno-29-133"></a><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">db</span>
</span><span id="__span-29-134"><a id="__codelineno-29-134" name="__codelineno-29-134" href="#__codelineno-29-134"></a><span class="w"> </span><span class="p">.</span><span class="nx">update</span><span class="p">(</span><span class="nx">jobs</span><span class="p">)</span>
</span><span id="__span-29-135"><a id="__codelineno-29-135" name="__codelineno-29-135" href="#__codelineno-29-135"></a><span class="w"> </span><span class="p">.</span><span class="nx">set</span><span class="p">({</span>
</span><span id="__span-29-136"><a id="__codelineno-29-136" name="__codelineno-29-136" href="#__codelineno-29-136"></a><span class="w"> </span><span class="nx">status</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;failed&#39;</span><span class="p">,</span>
</span><span id="__span-29-137"><a id="__codelineno-29-137" name="__codelineno-29-137" href="#__codelineno-29-137"></a><span class="w"> </span><span class="nx">log</span><span class="o">:</span><span class="w"> </span><span class="p">(</span><span class="nx">job</span><span class="p">.</span><span class="nx">log</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="s1">&#39;&#39;</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="sb">`\n\n--- ERROR ---\n</span><span class="si">${</span><span class="nx">error</span><span class="p">.</span><span class="nx">message</span><span class="si">}</span><span class="sb">`</span><span class="p">,</span>
</span><span id="__span-29-138"><a id="__codelineno-29-138" name="__codelineno-29-138" href="#__codelineno-29-138"></a><span class="w"> </span><span class="p">})</span>
</span><span id="__span-29-139"><a id="__codelineno-29-139" name="__codelineno-29-139" href="#__codelineno-29-139"></a><span class="w"> </span><span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="nx">eq</span><span class="p">(</span><span class="nx">jobs</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="nx">job</span><span class="p">.</span><span class="nx">id</span><span class="p">));</span>
</span><span id="__span-29-140"><a id="__codelineno-29-140" name="__codelineno-29-140" href="#__codelineno-29-140"></a>
</span><span id="__span-29-141"><a id="__codelineno-29-141" name="__codelineno-29-141" href="#__codelineno-29-141"></a><span class="w"> </span><span class="c1">// Schedule retry if under max retries</span>
</span><span id="__span-29-142"><a id="__codelineno-29-142" name="__codelineno-29-142" href="#__codelineno-29-142"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">job</span><span class="p">.</span><span class="nx">retryCount</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="nx">job</span><span class="p">.</span><span class="nx">maxRetries</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-143"><a id="__codelineno-29-143" name="__codelineno-29-143" href="#__codelineno-29-143"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">retryDelay</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Math</span><span class="p">.</span><span class="nx">pow</span><span class="p">(</span><span class="mf">2</span><span class="p">,</span><span class="w"> </span><span class="nx">job</span><span class="p">.</span><span class="nx">retryCount</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mf">60</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mf">1000</span><span class="p">;</span><span class="w"> </span><span class="c1">// Exponential backoff</span>
</span><span id="__span-29-144"><a id="__codelineno-29-144" name="__codelineno-29-144" href="#__codelineno-29-144"></a><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">db</span>
</span><span id="__span-29-145"><a id="__codelineno-29-145" name="__codelineno-29-145" href="#__codelineno-29-145"></a><span class="w"> </span><span class="p">.</span><span class="nx">update</span><span class="p">(</span><span class="nx">jobs</span><span class="p">)</span>
</span><span id="__span-29-146"><a id="__codelineno-29-146" name="__codelineno-29-146" href="#__codelineno-29-146"></a><span class="w"> </span><span class="p">.</span><span class="nx">set</span><span class="p">({</span>
</span><span id="__span-29-147"><a id="__codelineno-29-147" name="__codelineno-29-147" href="#__codelineno-29-147"></a><span class="w"> </span><span class="nx">status</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;pending&#39;</span><span class="p">,</span>
</span><span id="__span-29-148"><a id="__codelineno-29-148" name="__codelineno-29-148" href="#__codelineno-29-148"></a><span class="w"> </span><span class="nx">retryCount</span><span class="o">:</span><span class="w"> </span><span class="kt">job.retryCount</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mf">1</span><span class="p">,</span>
</span><span id="__span-29-149"><a id="__codelineno-29-149" name="__codelineno-29-149" href="#__codelineno-29-149"></a><span class="w"> </span><span class="nx">retryAfter</span><span class="o">:</span><span class="w"> </span><span class="kt">new</span><span class="w"> </span><span class="nb">Date</span><span class="p">(</span><span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">retryDelay</span><span class="p">),</span>
</span><span id="__span-29-150"><a id="__codelineno-29-150" name="__codelineno-29-150" href="#__codelineno-29-150"></a><span class="w"> </span><span class="p">})</span>
</span><span id="__span-29-151"><a id="__codelineno-29-151" name="__codelineno-29-151" href="#__codelineno-29-151"></a><span class="w"> </span><span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="nx">eq</span><span class="p">(</span><span class="nx">jobs</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="nx">job</span><span class="p">.</span><span class="nx">id</span><span class="p">));</span>
</span><span id="__span-29-152"><a id="__codelineno-29-152" name="__codelineno-29-152" href="#__codelineno-29-152"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-29-153"><a id="__codelineno-29-153" name="__codelineno-29-153" href="#__codelineno-29-153"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-29-154"><a id="__codelineno-29-154" name="__codelineno-29-154" href="#__codelineno-29-154"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-29-155"><a id="__codelineno-29-155" name="__codelineno-29-155" href="#__codelineno-29-155"></a>
</span><span id="__span-29-156"><a id="__codelineno-29-156" name="__codelineno-29-156" href="#__codelineno-29-156"></a><span class="w"> </span><span class="k">private</span><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="nx">executeReencode</span><span class="p">(</span><span class="nx">job</span><span class="o">:</span><span class="w"> </span><span class="kt">any</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-157"><a id="__codelineno-29-157" name="__codelineno-29-157" href="#__codelineno-29-157"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">inputPath</span><span class="p">,</span><span class="w"> </span><span class="nx">outputPath</span><span class="p">,</span><span class="w"> </span><span class="nx">targetBitrate</span><span class="p">,</span><span class="w"> </span><span class="nx">preset</span><span class="p">,</span><span class="w"> </span><span class="nx">crf</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">job</span><span class="p">.</span><span class="nx">params</span><span class="p">;</span>
</span><span id="__span-29-158"><a id="__codelineno-29-158" name="__codelineno-29-158" href="#__codelineno-29-158"></a>
</span><span id="__span-29-159"><a id="__codelineno-29-159" name="__codelineno-29-159" href="#__codelineno-29-159"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">inputFull</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">MEDIA_LIBRARY_PATH</span><span class="o">!</span><span class="p">,</span><span class="w"> </span><span class="nx">inputPath</span><span class="p">);</span>
</span><span id="__span-29-160"><a id="__codelineno-29-160" name="__codelineno-29-160" href="#__codelineno-29-160"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">outputFull</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">MEDIA_LIBRARY_PATH</span><span class="o">!</span><span class="p">,</span><span class="w"> </span><span class="nx">outputPath</span><span class="p">);</span>
</span><span id="__span-29-161"><a id="__codelineno-29-161" name="__codelineno-29-161" href="#__codelineno-29-161"></a>
</span><span id="__span-29-162"><a id="__codelineno-29-162" name="__codelineno-29-162" href="#__codelineno-29-162"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">command</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sb">`ffmpeg -i &quot;</span><span class="si">${</span><span class="nx">inputFull</span><span class="si">}</span><span class="sb">&quot; -c:v libx264 -preset </span><span class="si">${</span><span class="nx">preset</span><span class="si">}</span><span class="sb"> -crf </span><span class="si">${</span><span class="nx">crf</span><span class="si">}</span><span class="sb"> -maxrate </span><span class="si">${</span><span class="nx">targetBitrate</span><span class="si">}</span><span class="sb">k -bufsize </span><span class="si">${</span><span class="nx">targetBitrate</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mf">2</span><span class="si">}</span><span class="sb">k -c:a aac -b:a 128k -movflags +faststart &quot;</span><span class="si">${</span><span class="nx">outputFull</span><span class="si">}</span><span class="sb">&quot;`</span><span class="p">;</span>
</span><span id="__span-29-163"><a id="__codelineno-29-163" name="__codelineno-29-163" href="#__codelineno-29-163"></a>
</span><span id="__span-29-164"><a id="__codelineno-29-164" name="__codelineno-29-164" href="#__codelineno-29-164"></a><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">appendLog</span><span class="p">(</span><span class="nx">job</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="sb">`Starting re-encode\nCommand: </span><span class="si">${</span><span class="nx">command</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span><span id="__span-29-165"><a id="__codelineno-29-165" name="__codelineno-29-165" href="#__codelineno-29-165"></a>
</span><span id="__span-29-166"><a id="__codelineno-29-166" name="__codelineno-29-166" href="#__codelineno-29-166"></a><span class="w"> </span><span class="c1">// Execute FFmpeg (simplified - real implementation uses spawn for progress parsing)</span>
</span><span id="__span-29-167"><a id="__codelineno-29-167" name="__codelineno-29-167" href="#__codelineno-29-167"></a><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">execAsync</span><span class="p">(</span><span class="nx">command</span><span class="p">);</span>
</span><span id="__span-29-168"><a id="__codelineno-29-168" name="__codelineno-29-168" href="#__codelineno-29-168"></a>
</span><span id="__span-29-169"><a id="__codelineno-29-169" name="__codelineno-29-169" href="#__codelineno-29-169"></a><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">appendLog</span><span class="p">(</span><span class="nx">job</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Re-encode completed successfully&#39;</span><span class="p">);</span>
</span><span id="__span-29-170"><a id="__codelineno-29-170" name="__codelineno-29-170" href="#__codelineno-29-170"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-29-171"><a id="__codelineno-29-171" name="__codelineno-29-171" href="#__codelineno-29-171"></a>
</span><span id="__span-29-172"><a id="__codelineno-29-172" name="__codelineno-29-172" href="#__codelineno-29-172"></a><span class="w"> </span><span class="k">private</span><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="nx">appendLog</span><span class="p">(</span><span class="nx">jobId</span><span class="o">:</span><span class="w"> </span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="nx">message</span><span class="o">:</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-29-173"><a id="__codelineno-29-173" name="__codelineno-29-173" href="#__codelineno-29-173"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">timestamp</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nb">Date</span><span class="p">().</span><span class="nx">toISOString</span><span class="p">();</span>
</span><span id="__span-29-174"><a id="__codelineno-29-174" name="__codelineno-29-174" href="#__codelineno-29-174"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">logEntry</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="sb">`[</span><span class="si">${</span><span class="nx">timestamp</span><span class="si">}</span><span class="sb">] </span><span class="si">${</span><span class="nx">message</span><span class="si">}</span><span class="sb">`</span><span class="p">;</span>
</span><span id="__span-29-175"><a id="__codelineno-29-175" name="__codelineno-29-175" href="#__codelineno-29-175"></a>
</span><span id="__span-29-176"><a id="__codelineno-29-176" name="__codelineno-29-176" href="#__codelineno-29-176"></a><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">db</span>
</span><span id="__span-29-177"><a id="__codelineno-29-177" name="__codelineno-29-177" href="#__codelineno-29-177"></a><span class="w"> </span><span class="p">.</span><span class="nx">update</span><span class="p">(</span><span class="nx">jobs</span><span class="p">)</span>
</span><span id="__span-29-178"><a id="__codelineno-29-178" name="__codelineno-29-178" href="#__codelineno-29-178"></a><span class="w"> </span><span class="p">.</span><span class="nx">set</span><span class="p">({</span>
</span><span id="__span-29-179"><a id="__codelineno-29-179" name="__codelineno-29-179" href="#__codelineno-29-179"></a><span class="w"> </span><span class="nx">log</span><span class="o">:</span><span class="w"> </span><span class="kt">sql</span><span class="sb">`</span><span class="si">${</span><span class="nx">jobs</span><span class="p">.</span><span class="nx">log</span><span class="si">}</span><span class="sb"> || E&#39;\n&#39; || </span><span class="si">${</span><span class="nx">logEntry</span><span class="si">}</span><span class="sb">`</span><span class="p">,</span>
</span><span id="__span-29-180"><a id="__codelineno-29-180" name="__codelineno-29-180" href="#__codelineno-29-180"></a><span class="w"> </span><span class="p">})</span>
</span><span id="__span-29-181"><a id="__codelineno-29-181" name="__codelineno-29-181" href="#__codelineno-29-181"></a><span class="w"> </span><span class="p">.</span><span class="nx">where</span><span class="p">(</span><span class="nx">eq</span><span class="p">(</span><span class="nx">jobs</span><span class="p">.</span><span class="nx">id</span><span class="p">,</span><span class="w"> </span><span class="nx">jobId</span><span class="p">));</span>
</span><span id="__span-29-182"><a id="__codelineno-29-182" name="__codelineno-29-182" href="#__codelineno-29-182"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-29-183"><a id="__codelineno-29-183" name="__codelineno-29-183" href="#__codelineno-29-183"></a><span class="p">}</span>
</span><span id="__span-29-184"><a id="__codelineno-29-184" name="__codelineno-29-184" href="#__codelineno-29-184"></a>
</span><span id="__span-29-185"><a id="__codelineno-29-185" name="__codelineno-29-185" href="#__codelineno-29-185"></a><span class="c1">// Start worker</span>
</span><span id="__span-29-186"><a id="__codelineno-29-186" name="__codelineno-29-186" href="#__codelineno-29-186"></a><span class="k">export</span><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">jobWorker</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nx">JobWorkerService</span><span class="p">();</span>
</span><span id="__span-29-187"><a id="__codelineno-29-187" name="__codelineno-29-187" href="#__codelineno-29-187"></a><span class="nx">jobWorker</span><span class="p">.</span><span class="nx">start</span><span class="p">();</span>
</span></code></pre></div>
<hr />
<h3 id="frontend-jobs-page">Frontend: Jobs Page<a class="headerlink" href="#frontend-jobs-page" title="Permanent link">&para;</a></h3>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-30-1"><a id="__codelineno-30-1" name="__codelineno-30-1" href="#__codelineno-30-1"></a><span class="c1">// admin/src/pages/media/MediaJobsPage.tsx</span>
</span><span id="__span-30-2"><a id="__codelineno-30-2" name="__codelineno-30-2" href="#__codelineno-30-2"></a><span class="k">import</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">Table</span><span class="p">,</span><span class="w"> </span><span class="nx">Tag</span><span class="p">,</span><span class="w"> </span><span class="nx">Progress</span><span class="p">,</span><span class="w"> </span><span class="nx">Button</span><span class="p">,</span><span class="w"> </span><span class="nx">Space</span><span class="p">,</span><span class="w"> </span><span class="nx">Select</span><span class="p">,</span><span class="w"> </span><span class="nx">message</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="kr">from</span><span class="w"> </span><span class="s1">&#39;antd&#39;</span><span class="p">;</span>
</span><span id="__span-30-3"><a id="__codelineno-30-3" name="__codelineno-30-3" href="#__codelineno-30-3"></a><span class="k">import</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">useEffect</span><span class="p">,</span><span class="w"> </span><span class="nx">useState</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="kr">from</span><span class="w"> </span><span class="s1">&#39;react&#39;</span><span class="p">;</span>
</span><span id="__span-30-4"><a id="__codelineno-30-4" name="__codelineno-30-4" href="#__codelineno-30-4"></a><span class="k">import</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">mediaApi</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="kr">from</span><span class="w"> </span><span class="s1">&#39;@/lib/media-api&#39;</span><span class="p">;</span>
</span><span id="__span-30-5"><a id="__codelineno-30-5" name="__codelineno-30-5" href="#__codelineno-30-5"></a>
</span><span id="__span-30-6"><a id="__codelineno-30-6" name="__codelineno-30-6" href="#__codelineno-30-6"></a><span class="k">export</span><span class="w"> </span><span class="k">default</span><span class="w"> </span><span class="kd">function</span><span class="w"> </span><span class="nx">MediaJobsPage</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-7"><a id="__codelineno-30-7" name="__codelineno-30-7" href="#__codelineno-30-7"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="p">[</span><span class="nx">jobs</span><span class="p">,</span><span class="w"> </span><span class="nx">setJobs</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">useState</span><span class="p">([]);</span>
</span><span id="__span-30-8"><a id="__codelineno-30-8" name="__codelineno-30-8" href="#__codelineno-30-8"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="p">[</span><span class="nx">loading</span><span class="p">,</span><span class="w"> </span><span class="nx">setLoading</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">useState</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span>
</span><span id="__span-30-9"><a id="__codelineno-30-9" name="__codelineno-30-9" href="#__codelineno-30-9"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="p">[</span><span class="nx">filter</span><span class="p">,</span><span class="w"> </span><span class="nx">setFilter</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">useState</span><span class="p">({</span><span class="w"> </span><span class="nx">status</span><span class="o">:</span><span class="w"> </span><span class="kt">undefined</span><span class="p">,</span><span class="w"> </span><span class="kr">type</span><span class="o">:</span><span class="w"> </span><span class="kc">undefined</span><span class="w"> </span><span class="p">});</span>
</span><span id="__span-30-10"><a id="__codelineno-30-10" name="__codelineno-30-10" href="#__codelineno-30-10"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="p">[</span><span class="nx">polling</span><span class="p">,</span><span class="w"> </span><span class="nx">setPolling</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">useState</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>
</span><span id="__span-30-11"><a id="__codelineno-30-11" name="__codelineno-30-11" href="#__codelineno-30-11"></a>
</span><span id="__span-30-12"><a id="__codelineno-30-12" name="__codelineno-30-12" href="#__codelineno-30-12"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">fetchJobs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-13"><a id="__codelineno-30-13" name="__codelineno-30-13" href="#__codelineno-30-13"></a><span class="w"> </span><span class="nx">setLoading</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>
</span><span id="__span-30-14"><a id="__codelineno-30-14" name="__codelineno-30-14" href="#__codelineno-30-14"></a><span class="w"> </span><span class="k">try</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-15"><a id="__codelineno-30-15" name="__codelineno-30-15" href="#__codelineno-30-15"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">data</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">mediaApi</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;/api/media/jobs&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-16"><a id="__codelineno-30-16" name="__codelineno-30-16" href="#__codelineno-30-16"></a><span class="w"> </span><span class="nx">params</span><span class="o">:</span><span class="w"> </span><span class="kt">filter</span><span class="p">,</span>
</span><span id="__span-30-17"><a id="__codelineno-30-17" name="__codelineno-30-17" href="#__codelineno-30-17"></a><span class="w"> </span><span class="p">});</span>
</span><span id="__span-30-18"><a id="__codelineno-30-18" name="__codelineno-30-18" href="#__codelineno-30-18"></a><span class="w"> </span><span class="nx">setJobs</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">data</span><span class="p">);</span>
</span><span id="__span-30-19"><a id="__codelineno-30-19" name="__codelineno-30-19" href="#__codelineno-30-19"></a><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">catch</span><span class="w"> </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-20"><a id="__codelineno-30-20" name="__codelineno-30-20" href="#__codelineno-30-20"></a><span class="w"> </span><span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s1">&#39;Failed to fetch jobs:&#39;</span><span class="p">,</span><span class="w"> </span><span class="nx">error</span><span class="p">);</span>
</span><span id="__span-30-21"><a id="__codelineno-30-21" name="__codelineno-30-21" href="#__codelineno-30-21"></a><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">finally</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-22"><a id="__codelineno-30-22" name="__codelineno-30-22" href="#__codelineno-30-22"></a><span class="w"> </span><span class="nx">setLoading</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span>
</span><span id="__span-30-23"><a id="__codelineno-30-23" name="__codelineno-30-23" href="#__codelineno-30-23"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-30-24"><a id="__codelineno-30-24" name="__codelineno-30-24" href="#__codelineno-30-24"></a><span class="w"> </span><span class="p">};</span>
</span><span id="__span-30-25"><a id="__codelineno-30-25" name="__codelineno-30-25" href="#__codelineno-30-25"></a>
</span><span id="__span-30-26"><a id="__codelineno-30-26" name="__codelineno-30-26" href="#__codelineno-30-26"></a><span class="w"> </span><span class="nx">useEffect</span><span class="p">(()</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-27"><a id="__codelineno-30-27" name="__codelineno-30-27" href="#__codelineno-30-27"></a><span class="w"> </span><span class="nx">fetchJobs</span><span class="p">();</span>
</span><span id="__span-30-28"><a id="__codelineno-30-28" name="__codelineno-30-28" href="#__codelineno-30-28"></a><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">[</span><span class="nx">filter</span><span class="p">]);</span>
</span><span id="__span-30-29"><a id="__codelineno-30-29" name="__codelineno-30-29" href="#__codelineno-30-29"></a>
</span><span id="__span-30-30"><a id="__codelineno-30-30" name="__codelineno-30-30" href="#__codelineno-30-30"></a><span class="w"> </span><span class="c1">// Poll for running jobs every 2 seconds</span>
</span><span id="__span-30-31"><a id="__codelineno-30-31" name="__codelineno-30-31" href="#__codelineno-30-31"></a><span class="w"> </span><span class="nx">useEffect</span><span class="p">(()</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-32"><a id="__codelineno-30-32" name="__codelineno-30-32" href="#__codelineno-30-32"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="nx">polling</span><span class="p">)</span><span class="w"> </span><span class="k">return</span><span class="p">;</span>
</span><span id="__span-30-33"><a id="__codelineno-30-33" name="__codelineno-30-33" href="#__codelineno-30-33"></a>
</span><span id="__span-30-34"><a id="__codelineno-30-34" name="__codelineno-30-34" href="#__codelineno-30-34"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">interval</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">setInterval</span><span class="p">(()</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-35"><a id="__codelineno-30-35" name="__codelineno-30-35" href="#__codelineno-30-35"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">hasRunning</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">jobs</span><span class="p">.</span><span class="nx">some</span><span class="p">((</span><span class="nx">j</span><span class="o">:</span><span class="w"> </span><span class="kt">any</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="nx">j</span><span class="p">.</span><span class="nx">status</span><span class="w"> </span><span class="o">===</span><span class="w"> </span><span class="s1">&#39;running&#39;</span><span class="p">);</span>
</span><span id="__span-30-36"><a id="__codelineno-30-36" name="__codelineno-30-36" href="#__codelineno-30-36"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">hasRunning</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-37"><a id="__codelineno-30-37" name="__codelineno-30-37" href="#__codelineno-30-37"></a><span class="w"> </span><span class="nx">fetchJobs</span><span class="p">();</span>
</span><span id="__span-30-38"><a id="__codelineno-30-38" name="__codelineno-30-38" href="#__codelineno-30-38"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-30-39"><a id="__codelineno-30-39" name="__codelineno-30-39" href="#__codelineno-30-39"></a><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="mf">2000</span><span class="p">);</span>
</span><span id="__span-30-40"><a id="__codelineno-30-40" name="__codelineno-30-40" href="#__codelineno-30-40"></a>
</span><span id="__span-30-41"><a id="__codelineno-30-41" name="__codelineno-30-41" href="#__codelineno-30-41"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="nx">clearInterval</span><span class="p">(</span><span class="nx">interval</span><span class="p">);</span>
</span><span id="__span-30-42"><a id="__codelineno-30-42" name="__codelineno-30-42" href="#__codelineno-30-42"></a><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">[</span><span class="nx">polling</span><span class="p">,</span><span class="w"> </span><span class="nx">jobs</span><span class="p">]);</span>
</span><span id="__span-30-43"><a id="__codelineno-30-43" name="__codelineno-30-43" href="#__codelineno-30-43"></a>
</span><span id="__span-30-44"><a id="__codelineno-30-44" name="__codelineno-30-44" href="#__codelineno-30-44"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">handleRetry</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="p">(</span><span class="nx">id</span><span class="o">:</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-45"><a id="__codelineno-30-45" name="__codelineno-30-45" href="#__codelineno-30-45"></a><span class="w"> </span><span class="k">try</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-46"><a id="__codelineno-30-46" name="__codelineno-30-46" href="#__codelineno-30-46"></a><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">mediaApi</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="sb">`/api/media/jobs/</span><span class="si">${</span><span class="nx">id</span><span class="si">}</span><span class="sb">/retry`</span><span class="p">);</span>
</span><span id="__span-30-47"><a id="__codelineno-30-47" name="__codelineno-30-47" href="#__codelineno-30-47"></a><span class="w"> </span><span class="nx">message</span><span class="p">.</span><span class="nx">success</span><span class="p">(</span><span class="s1">&#39;Job queued for retry&#39;</span><span class="p">);</span>
</span><span id="__span-30-48"><a id="__codelineno-30-48" name="__codelineno-30-48" href="#__codelineno-30-48"></a><span class="w"> </span><span class="nx">fetchJobs</span><span class="p">();</span>
</span><span id="__span-30-49"><a id="__codelineno-30-49" name="__codelineno-30-49" href="#__codelineno-30-49"></a><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">catch</span><span class="w"> </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-50"><a id="__codelineno-30-50" name="__codelineno-30-50" href="#__codelineno-30-50"></a><span class="w"> </span><span class="nx">message</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s1">&#39;Retry failed&#39;</span><span class="p">);</span>
</span><span id="__span-30-51"><a id="__codelineno-30-51" name="__codelineno-30-51" href="#__codelineno-30-51"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-30-52"><a id="__codelineno-30-52" name="__codelineno-30-52" href="#__codelineno-30-52"></a><span class="w"> </span><span class="p">};</span>
</span><span id="__span-30-53"><a id="__codelineno-30-53" name="__codelineno-30-53" href="#__codelineno-30-53"></a>
</span><span id="__span-30-54"><a id="__codelineno-30-54" name="__codelineno-30-54" href="#__codelineno-30-54"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">handleCancel</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">async</span><span class="w"> </span><span class="p">(</span><span class="nx">id</span><span class="o">:</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-55"><a id="__codelineno-30-55" name="__codelineno-30-55" href="#__codelineno-30-55"></a><span class="w"> </span><span class="k">try</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-56"><a id="__codelineno-30-56" name="__codelineno-30-56" href="#__codelineno-30-56"></a><span class="w"> </span><span class="k">await</span><span class="w"> </span><span class="nx">mediaApi</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="sb">`/api/media/jobs/</span><span class="si">${</span><span class="nx">id</span><span class="si">}</span><span class="sb">/cancel`</span><span class="p">);</span>
</span><span id="__span-30-57"><a id="__codelineno-30-57" name="__codelineno-30-57" href="#__codelineno-30-57"></a><span class="w"> </span><span class="nx">message</span><span class="p">.</span><span class="nx">success</span><span class="p">(</span><span class="s1">&#39;Job cancelled&#39;</span><span class="p">);</span>
</span><span id="__span-30-58"><a id="__codelineno-30-58" name="__codelineno-30-58" href="#__codelineno-30-58"></a><span class="w"> </span><span class="nx">fetchJobs</span><span class="p">();</span>
</span><span id="__span-30-59"><a id="__codelineno-30-59" name="__codelineno-30-59" href="#__codelineno-30-59"></a><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">catch</span><span class="w"> </span><span class="p">(</span><span class="nx">error</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-60"><a id="__codelineno-30-60" name="__codelineno-30-60" href="#__codelineno-30-60"></a><span class="w"> </span><span class="nx">message</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s1">&#39;Cancel failed&#39;</span><span class="p">);</span>
</span><span id="__span-30-61"><a id="__codelineno-30-61" name="__codelineno-30-61" href="#__codelineno-30-61"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-30-62"><a id="__codelineno-30-62" name="__codelineno-30-62" href="#__codelineno-30-62"></a><span class="w"> </span><span class="p">};</span>
</span><span id="__span-30-63"><a id="__codelineno-30-63" name="__codelineno-30-63" href="#__codelineno-30-63"></a>
</span><span id="__span-30-64"><a id="__codelineno-30-64" name="__codelineno-30-64" href="#__codelineno-30-64"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">statusColors</span><span class="o">:</span><span class="w"> </span><span class="kt">Record</span><span class="o">&lt;</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kt">string</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-65"><a id="__codelineno-30-65" name="__codelineno-30-65" href="#__codelineno-30-65"></a><span class="w"> </span><span class="nx">pending</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;default&#39;</span><span class="p">,</span>
</span><span id="__span-30-66"><a id="__codelineno-30-66" name="__codelineno-30-66" href="#__codelineno-30-66"></a><span class="w"> </span><span class="nx">queued</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;blue&#39;</span><span class="p">,</span>
</span><span id="__span-30-67"><a id="__codelineno-30-67" name="__codelineno-30-67" href="#__codelineno-30-67"></a><span class="w"> </span><span class="nx">running</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;processing&#39;</span><span class="p">,</span>
</span><span id="__span-30-68"><a id="__codelineno-30-68" name="__codelineno-30-68" href="#__codelineno-30-68"></a><span class="w"> </span><span class="nx">completed</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;success&#39;</span><span class="p">,</span>
</span><span id="__span-30-69"><a id="__codelineno-30-69" name="__codelineno-30-69" href="#__codelineno-30-69"></a><span class="w"> </span><span class="nx">failed</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;error&#39;</span><span class="p">,</span>
</span><span id="__span-30-70"><a id="__codelineno-30-70" name="__codelineno-30-70" href="#__codelineno-30-70"></a><span class="w"> </span><span class="nx">cancelled</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;default&#39;</span><span class="p">,</span>
</span><span id="__span-30-71"><a id="__codelineno-30-71" name="__codelineno-30-71" href="#__codelineno-30-71"></a><span class="w"> </span><span class="nx">paused</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;warning&#39;</span><span class="p">,</span>
</span><span id="__span-30-72"><a id="__codelineno-30-72" name="__codelineno-30-72" href="#__codelineno-30-72"></a><span class="w"> </span><span class="p">};</span>
</span><span id="__span-30-73"><a id="__codelineno-30-73" name="__codelineno-30-73" href="#__codelineno-30-73"></a>
</span><span id="__span-30-74"><a id="__codelineno-30-74" name="__codelineno-30-74" href="#__codelineno-30-74"></a><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">columns</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span>
</span><span id="__span-30-75"><a id="__codelineno-30-75" name="__codelineno-30-75" href="#__codelineno-30-75"></a><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-76"><a id="__codelineno-30-76" name="__codelineno-30-76" href="#__codelineno-30-76"></a><span class="w"> </span><span class="nx">title</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;Type&#39;</span><span class="p">,</span>
</span><span id="__span-30-77"><a id="__codelineno-30-77" name="__codelineno-30-77" href="#__codelineno-30-77"></a><span class="w"> </span><span class="nx">dataIndex</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;type&#39;</span><span class="p">,</span>
</span><span id="__span-30-78"><a id="__codelineno-30-78" name="__codelineno-30-78" href="#__codelineno-30-78"></a><span class="w"> </span><span class="nx">width</span><span class="o">:</span><span class="w"> </span><span class="kt">150</span><span class="p">,</span>
</span><span id="__span-30-79"><a id="__codelineno-30-79" name="__codelineno-30-79" href="#__codelineno-30-79"></a><span class="w"> </span><span class="nx">render</span><span class="o">:</span><span class="w"> </span><span class="p">(</span><span class="kr">type</span><span class="o">:</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="o">&lt;</span><span class="nx">span</span><span class="w"> </span><span class="nx">style</span><span class="o">=</span><span class="p">{{</span><span class="w"> </span><span class="nx">fontFamily</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;monospace&#39;</span><span class="w"> </span><span class="p">}}</span><span class="o">&gt;</span><span class="p">{</span><span class="kr">type</span><span class="p">}</span><span class="o">&lt;</span><span class="err">/span&gt;,</span>
</span><span id="__span-30-80"><a id="__codelineno-30-80" name="__codelineno-30-80" href="#__codelineno-30-80"></a><span class="w"> </span><span class="p">},</span>
</span><span id="__span-30-81"><a id="__codelineno-30-81" name="__codelineno-30-81" href="#__codelineno-30-81"></a><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-82"><a id="__codelineno-30-82" name="__codelineno-30-82" href="#__codelineno-30-82"></a><span class="w"> </span><span class="nx">title</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;Status&#39;</span><span class="p">,</span>
</span><span id="__span-30-83"><a id="__codelineno-30-83" name="__codelineno-30-83" href="#__codelineno-30-83"></a><span class="w"> </span><span class="nx">dataIndex</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;status&#39;</span><span class="p">,</span>
</span><span id="__span-30-84"><a id="__codelineno-30-84" name="__codelineno-30-84" href="#__codelineno-30-84"></a><span class="w"> </span><span class="nx">width</span><span class="o">:</span><span class="w"> </span><span class="kt">100</span><span class="p">,</span>
</span><span id="__span-30-85"><a id="__codelineno-30-85" name="__codelineno-30-85" href="#__codelineno-30-85"></a><span class="w"> </span><span class="nx">render</span><span class="o">:</span><span class="w"> </span><span class="p">(</span><span class="nx">status</span><span class="o">:</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="o">&lt;</span><span class="nx">Tag</span><span class="w"> </span><span class="nx">color</span><span class="o">=</span><span class="p">{</span><span class="nx">statusColors</span><span class="p">[</span><span class="nx">status</span><span class="p">]}</span><span class="o">&gt;</span><span class="p">{</span><span class="nx">status</span><span class="p">.</span><span class="nx">toUpperCase</span><span class="p">()}</span><span class="o">&lt;</span><span class="err">/Tag&gt;,</span>
</span><span id="__span-30-86"><a id="__codelineno-30-86" name="__codelineno-30-86" href="#__codelineno-30-86"></a><span class="w"> </span><span class="p">},</span>
</span><span id="__span-30-87"><a id="__codelineno-30-87" name="__codelineno-30-87" href="#__codelineno-30-87"></a><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-88"><a id="__codelineno-30-88" name="__codelineno-30-88" href="#__codelineno-30-88"></a><span class="w"> </span><span class="nx">title</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;Progress&#39;</span><span class="p">,</span>
</span><span id="__span-30-89"><a id="__codelineno-30-89" name="__codelineno-30-89" href="#__codelineno-30-89"></a><span class="w"> </span><span class="nx">dataIndex</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;progress&#39;</span><span class="p">,</span>
</span><span id="__span-30-90"><a id="__codelineno-30-90" name="__codelineno-30-90" href="#__codelineno-30-90"></a><span class="w"> </span><span class="nx">width</span><span class="o">:</span><span class="w"> </span><span class="kt">150</span><span class="p">,</span>
</span><span id="__span-30-91"><a id="__codelineno-30-91" name="__codelineno-30-91" href="#__codelineno-30-91"></a><span class="w"> </span><span class="nx">render</span><span class="o">:</span><span class="w"> </span><span class="p">(</span><span class="nx">progress</span><span class="o">:</span><span class="w"> </span><span class="kt">number</span><span class="p">,</span><span class="w"> </span><span class="nx">record</span><span class="o">:</span><span class="w"> </span><span class="kt">any</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">(</span>
</span><span id="__span-30-92"><a id="__codelineno-30-92" name="__codelineno-30-92" href="#__codelineno-30-92"></a><span class="w"> </span><span class="nx">record</span><span class="p">.</span><span class="nx">status</span><span class="w"> </span><span class="o">===</span><span class="w"> </span><span class="s1">&#39;running&#39;</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="p">(</span>
</span><span id="__span-30-93"><a id="__codelineno-30-93" name="__codelineno-30-93" href="#__codelineno-30-93"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Progress</span><span class="w"> </span><span class="nx">percent</span><span class="o">=</span><span class="p">{</span><span class="nx">progress</span><span class="p">}</span><span class="w"> </span><span class="nx">size</span><span class="o">=</span><span class="s2">&quot;small&quot;</span><span class="w"> </span><span class="nx">status</span><span class="o">=</span><span class="s2">&quot;active&quot;</span><span class="w"> </span><span class="o">/&gt;</span>
</span><span id="__span-30-94"><a id="__codelineno-30-94" name="__codelineno-30-94" href="#__codelineno-30-94"></a><span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="nx">record</span><span class="p">.</span><span class="nx">status</span><span class="w"> </span><span class="o">===</span><span class="w"> </span><span class="s1">&#39;completed&#39;</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="p">(</span>
</span><span id="__span-30-95"><a id="__codelineno-30-95" name="__codelineno-30-95" href="#__codelineno-30-95"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Progress</span><span class="w"> </span><span class="nx">percent</span><span class="o">=</span><span class="p">{</span><span class="mf">100</span><span class="p">}</span><span class="w"> </span><span class="nx">size</span><span class="o">=</span><span class="s2">&quot;small&quot;</span><span class="w"> </span><span class="nx">status</span><span class="o">=</span><span class="s2">&quot;success&quot;</span><span class="w"> </span><span class="o">/&gt;</span>
</span><span id="__span-30-96"><a id="__codelineno-30-96" name="__codelineno-30-96" href="#__codelineno-30-96"></a><span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="nx">record</span><span class="p">.</span><span class="nx">status</span><span class="w"> </span><span class="o">===</span><span class="w"> </span><span class="s1">&#39;failed&#39;</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="p">(</span>
</span><span id="__span-30-97"><a id="__codelineno-30-97" name="__codelineno-30-97" href="#__codelineno-30-97"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Progress</span><span class="w"> </span><span class="nx">percent</span><span class="o">=</span><span class="p">{</span><span class="nx">progress</span><span class="p">}</span><span class="w"> </span><span class="nx">size</span><span class="o">=</span><span class="s2">&quot;small&quot;</span><span class="w"> </span><span class="nx">status</span><span class="o">=</span><span class="s2">&quot;exception&quot;</span><span class="w"> </span><span class="o">/&gt;</span>
</span><span id="__span-30-98"><a id="__codelineno-30-98" name="__codelineno-30-98" href="#__codelineno-30-98"></a><span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="p">(</span>
</span><span id="__span-30-99"><a id="__codelineno-30-99" name="__codelineno-30-99" href="#__codelineno-30-99"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Progress</span><span class="w"> </span><span class="nx">percent</span><span class="o">=</span><span class="p">{</span><span class="nx">progress</span><span class="p">}</span><span class="w"> </span><span class="nx">size</span><span class="o">=</span><span class="s2">&quot;small&quot;</span><span class="w"> </span><span class="o">/&gt;</span>
</span><span id="__span-30-100"><a id="__codelineno-30-100" name="__codelineno-30-100" href="#__codelineno-30-100"></a><span class="w"> </span><span class="p">)</span>
</span><span id="__span-30-101"><a id="__codelineno-30-101" name="__codelineno-30-101" href="#__codelineno-30-101"></a><span class="w"> </span><span class="p">),</span>
</span><span id="__span-30-102"><a id="__codelineno-30-102" name="__codelineno-30-102" href="#__codelineno-30-102"></a><span class="w"> </span><span class="p">},</span>
</span><span id="__span-30-103"><a id="__codelineno-30-103" name="__codelineno-30-103" href="#__codelineno-30-103"></a><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-104"><a id="__codelineno-30-104" name="__codelineno-30-104" href="#__codelineno-30-104"></a><span class="w"> </span><span class="nx">title</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;Resource&#39;</span><span class="p">,</span>
</span><span id="__span-30-105"><a id="__codelineno-30-105" name="__codelineno-30-105" href="#__codelineno-30-105"></a><span class="w"> </span><span class="nx">dataIndex</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;resourceCategory&#39;</span><span class="p">,</span>
</span><span id="__span-30-106"><a id="__codelineno-30-106" name="__codelineno-30-106" href="#__codelineno-30-106"></a><span class="w"> </span><span class="nx">width</span><span class="o">:</span><span class="w"> </span><span class="kt">120</span><span class="p">,</span>
</span><span id="__span-30-107"><a id="__codelineno-30-107" name="__codelineno-30-107" href="#__codelineno-30-107"></a><span class="w"> </span><span class="p">},</span>
</span><span id="__span-30-108"><a id="__codelineno-30-108" name="__codelineno-30-108" href="#__codelineno-30-108"></a><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-109"><a id="__codelineno-30-109" name="__codelineno-30-109" href="#__codelineno-30-109"></a><span class="w"> </span><span class="nx">title</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;Priority&#39;</span><span class="p">,</span>
</span><span id="__span-30-110"><a id="__codelineno-30-110" name="__codelineno-30-110" href="#__codelineno-30-110"></a><span class="w"> </span><span class="nx">dataIndex</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;priority&#39;</span><span class="p">,</span>
</span><span id="__span-30-111"><a id="__codelineno-30-111" name="__codelineno-30-111" href="#__codelineno-30-111"></a><span class="w"> </span><span class="nx">width</span><span class="o">:</span><span class="w"> </span><span class="kt">80</span><span class="p">,</span>
</span><span id="__span-30-112"><a id="__codelineno-30-112" name="__codelineno-30-112" href="#__codelineno-30-112"></a><span class="w"> </span><span class="nx">render</span><span class="o">:</span><span class="w"> </span><span class="p">(</span><span class="nx">priority</span><span class="o">:</span><span class="w"> </span><span class="kt">number</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">(</span>
</span><span id="__span-30-113"><a id="__codelineno-30-113" name="__codelineno-30-113" href="#__codelineno-30-113"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Tag</span><span class="w"> </span><span class="nx">color</span><span class="o">=</span><span class="p">{</span><span class="nx">priority</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="mf">3</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="s1">&#39;red&#39;</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="nx">priority</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="mf">6</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="s1">&#39;orange&#39;</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;default&#39;</span><span class="p">}</span><span class="o">&gt;</span>
</span><span id="__span-30-114"><a id="__codelineno-30-114" name="__codelineno-30-114" href="#__codelineno-30-114"></a><span class="w"> </span><span class="p">{</span><span class="nx">priority</span><span class="p">}</span>
</span><span id="__span-30-115"><a id="__codelineno-30-115" name="__codelineno-30-115" href="#__codelineno-30-115"></a><span class="w"> </span><span class="o">&lt;</span><span class="err">/Tag&gt;</span>
</span><span id="__span-30-116"><a id="__codelineno-30-116" name="__codelineno-30-116" href="#__codelineno-30-116"></a><span class="w"> </span><span class="p">),</span>
</span><span id="__span-30-117"><a id="__codelineno-30-117" name="__codelineno-30-117" href="#__codelineno-30-117"></a><span class="w"> </span><span class="p">},</span>
</span><span id="__span-30-118"><a id="__codelineno-30-118" name="__codelineno-30-118" href="#__codelineno-30-118"></a><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-119"><a id="__codelineno-30-119" name="__codelineno-30-119" href="#__codelineno-30-119"></a><span class="w"> </span><span class="nx">title</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;Created&#39;</span><span class="p">,</span>
</span><span id="__span-30-120"><a id="__codelineno-30-120" name="__codelineno-30-120" href="#__codelineno-30-120"></a><span class="w"> </span><span class="nx">dataIndex</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;createdAt&#39;</span><span class="p">,</span>
</span><span id="__span-30-121"><a id="__codelineno-30-121" name="__codelineno-30-121" href="#__codelineno-30-121"></a><span class="w"> </span><span class="nx">width</span><span class="o">:</span><span class="w"> </span><span class="kt">150</span><span class="p">,</span>
</span><span id="__span-30-122"><a id="__codelineno-30-122" name="__codelineno-30-122" href="#__codelineno-30-122"></a><span class="w"> </span><span class="nx">render</span><span class="o">:</span><span class="w"> </span><span class="p">(</span><span class="nx">date</span><span class="o">:</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nb">Date</span><span class="p">(</span><span class="nx">date</span><span class="p">).</span><span class="nx">toLocaleString</span><span class="p">(),</span>
</span><span id="__span-30-123"><a id="__codelineno-30-123" name="__codelineno-30-123" href="#__codelineno-30-123"></a><span class="w"> </span><span class="p">},</span>
</span><span id="__span-30-124"><a id="__codelineno-30-124" name="__codelineno-30-124" href="#__codelineno-30-124"></a><span class="w"> </span><span class="p">{</span>
</span><span id="__span-30-125"><a id="__codelineno-30-125" name="__codelineno-30-125" href="#__codelineno-30-125"></a><span class="w"> </span><span class="nx">title</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;Actions&#39;</span><span class="p">,</span>
</span><span id="__span-30-126"><a id="__codelineno-30-126" name="__codelineno-30-126" href="#__codelineno-30-126"></a><span class="w"> </span><span class="nx">width</span><span class="o">:</span><span class="w"> </span><span class="kt">200</span><span class="p">,</span>
</span><span id="__span-30-127"><a id="__codelineno-30-127" name="__codelineno-30-127" href="#__codelineno-30-127"></a><span class="w"> </span><span class="nx">render</span><span class="o">:</span><span class="w"> </span><span class="p">(</span><span class="nx">_</span><span class="o">:</span><span class="w"> </span><span class="kt">any</span><span class="p">,</span><span class="w"> </span><span class="nx">record</span><span class="o">:</span><span class="w"> </span><span class="kt">any</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="p">(</span>
</span><span id="__span-30-128"><a id="__codelineno-30-128" name="__codelineno-30-128" href="#__codelineno-30-128"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Space</span><span class="o">&gt;</span>
</span><span id="__span-30-129"><a id="__codelineno-30-129" name="__codelineno-30-129" href="#__codelineno-30-129"></a><span class="w"> </span><span class="p">{</span><span class="nx">record</span><span class="p">.</span><span class="nx">status</span><span class="w"> </span><span class="o">===</span><span class="w"> </span><span class="s1">&#39;failed&#39;</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="p">(</span>
</span><span id="__span-30-130"><a id="__codelineno-30-130" name="__codelineno-30-130" href="#__codelineno-30-130"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Button</span><span class="w"> </span><span class="nx">size</span><span class="o">=</span><span class="s2">&quot;small&quot;</span><span class="w"> </span><span class="nx">onClick</span><span class="o">=</span><span class="p">{()</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="nx">handleRetry</span><span class="p">(</span><span class="nx">record</span><span class="p">.</span><span class="nx">id</span><span class="p">)}</span><span class="o">&gt;</span>
</span><span id="__span-30-131"><a id="__codelineno-30-131" name="__codelineno-30-131" href="#__codelineno-30-131"></a><span class="w"> </span><span class="nx">Retry</span>
</span><span id="__span-30-132"><a id="__codelineno-30-132" name="__codelineno-30-132" href="#__codelineno-30-132"></a><span class="w"> </span><span class="o">&lt;</span><span class="err">/Button&gt;</span>
</span><span id="__span-30-133"><a id="__codelineno-30-133" name="__codelineno-30-133" href="#__codelineno-30-133"></a><span class="w"> </span><span class="p">)}</span>
</span><span id="__span-30-134"><a id="__codelineno-30-134" name="__codelineno-30-134" href="#__codelineno-30-134"></a><span class="w"> </span><span class="p">{[</span><span class="s1">&#39;pending&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;queued&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;running&#39;</span><span class="p">].</span><span class="nx">includes</span><span class="p">(</span><span class="nx">record</span><span class="p">.</span><span class="nx">status</span><span class="p">)</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="p">(</span>
</span><span id="__span-30-135"><a id="__codelineno-30-135" name="__codelineno-30-135" href="#__codelineno-30-135"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Button</span><span class="w"> </span><span class="nx">size</span><span class="o">=</span><span class="s2">&quot;small&quot;</span><span class="w"> </span><span class="nx">danger</span><span class="w"> </span><span class="nx">onClick</span><span class="o">=</span><span class="p">{()</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="nx">handleCancel</span><span class="p">(</span><span class="nx">record</span><span class="p">.</span><span class="nx">id</span><span class="p">)}</span><span class="o">&gt;</span>
</span><span id="__span-30-136"><a id="__codelineno-30-136" name="__codelineno-30-136" href="#__codelineno-30-136"></a><span class="w"> </span><span class="nx">Cancel</span>
</span><span id="__span-30-137"><a id="__codelineno-30-137" name="__codelineno-30-137" href="#__codelineno-30-137"></a><span class="w"> </span><span class="o">&lt;</span><span class="err">/Button&gt;</span>
</span><span id="__span-30-138"><a id="__codelineno-30-138" name="__codelineno-30-138" href="#__codelineno-30-138"></a><span class="w"> </span><span class="p">)}</span>
</span><span id="__span-30-139"><a id="__codelineno-30-139" name="__codelineno-30-139" href="#__codelineno-30-139"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Button</span><span class="w"> </span><span class="nx">size</span><span class="o">=</span><span class="s2">&quot;small&quot;</span><span class="w"> </span><span class="nx">onClick</span><span class="o">=</span><span class="p">{()</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="nb">window</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span><span class="sb">`/app/media/jobs/</span><span class="si">${</span><span class="nx">record</span><span class="p">.</span><span class="nx">id</span><span class="si">}</span><span class="sb">`</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;_blank&#39;</span><span class="p">)}</span><span class="o">&gt;</span>
</span><span id="__span-30-140"><a id="__codelineno-30-140" name="__codelineno-30-140" href="#__codelineno-30-140"></a><span class="w"> </span><span class="nx">View</span><span class="w"> </span><span class="nx">Log</span>
</span><span id="__span-30-141"><a id="__codelineno-30-141" name="__codelineno-30-141" href="#__codelineno-30-141"></a><span class="w"> </span><span class="o">&lt;</span><span class="err">/Button&gt;</span>
</span><span id="__span-30-142"><a id="__codelineno-30-142" name="__codelineno-30-142" href="#__codelineno-30-142"></a><span class="w"> </span><span class="o">&lt;</span><span class="err">/Space&gt;</span>
</span><span id="__span-30-143"><a id="__codelineno-30-143" name="__codelineno-30-143" href="#__codelineno-30-143"></a><span class="w"> </span><span class="p">),</span>
</span><span id="__span-30-144"><a id="__codelineno-30-144" name="__codelineno-30-144" href="#__codelineno-30-144"></a><span class="w"> </span><span class="p">},</span>
</span><span id="__span-30-145"><a id="__codelineno-30-145" name="__codelineno-30-145" href="#__codelineno-30-145"></a><span class="w"> </span><span class="p">];</span>
</span><span id="__span-30-146"><a id="__codelineno-30-146" name="__codelineno-30-146" href="#__codelineno-30-146"></a>
</span><span id="__span-30-147"><a id="__codelineno-30-147" name="__codelineno-30-147" href="#__codelineno-30-147"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">(</span>
</span><span id="__span-30-148"><a id="__codelineno-30-148" name="__codelineno-30-148" href="#__codelineno-30-148"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">div</span><span class="o">&gt;</span>
</span><span id="__span-30-149"><a id="__codelineno-30-149" name="__codelineno-30-149" href="#__codelineno-30-149"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Space</span><span class="w"> </span><span class="nx">style</span><span class="o">=</span><span class="p">{{</span><span class="w"> </span><span class="nx">marginBottom</span><span class="o">:</span><span class="w"> </span><span class="kt">16</span><span class="w"> </span><span class="p">}}</span><span class="o">&gt;</span>
</span><span id="__span-30-150"><a id="__codelineno-30-150" name="__codelineno-30-150" href="#__codelineno-30-150"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Select</span>
</span><span id="__span-30-151"><a id="__codelineno-30-151" name="__codelineno-30-151" href="#__codelineno-30-151"></a><span class="w"> </span><span class="nx">placeholder</span><span class="o">=</span><span class="s2">&quot;Filter by status&quot;</span>
</span><span id="__span-30-152"><a id="__codelineno-30-152" name="__codelineno-30-152" href="#__codelineno-30-152"></a><span class="w"> </span><span class="nx">style</span><span class="o">=</span><span class="p">{{</span><span class="w"> </span><span class="nx">width</span><span class="o">:</span><span class="w"> </span><span class="kt">150</span><span class="w"> </span><span class="p">}}</span>
</span><span id="__span-30-153"><a id="__codelineno-30-153" name="__codelineno-30-153" href="#__codelineno-30-153"></a><span class="w"> </span><span class="nx">onChange</span><span class="o">=</span><span class="p">{(</span><span class="nx">value</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="nx">setFilter</span><span class="p">({</span><span class="w"> </span><span class="p">...</span><span class="nx">filter</span><span class="p">,</span><span class="w"> </span><span class="nx">status</span><span class="o">:</span><span class="w"> </span><span class="kt">value</span><span class="w"> </span><span class="p">})}</span>
</span><span id="__span-30-154"><a id="__codelineno-30-154" name="__codelineno-30-154" href="#__codelineno-30-154"></a><span class="w"> </span><span class="nx">allowClear</span>
</span><span id="__span-30-155"><a id="__codelineno-30-155" name="__codelineno-30-155" href="#__codelineno-30-155"></a><span class="w"> </span><span class="o">&gt;</span>
</span><span id="__span-30-156"><a id="__codelineno-30-156" name="__codelineno-30-156" href="#__codelineno-30-156"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Select</span><span class="p">.</span><span class="nx">Option</span><span class="w"> </span><span class="nx">value</span><span class="o">=</span><span class="s2">&quot;pending&quot;</span><span class="o">&gt;</span><span class="nx">Pending</span><span class="o">&lt;</span><span class="err">/Select.Option&gt;</span>
</span><span id="__span-30-157"><a id="__codelineno-30-157" name="__codelineno-30-157" href="#__codelineno-30-157"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Select</span><span class="p">.</span><span class="nx">Option</span><span class="w"> </span><span class="nx">value</span><span class="o">=</span><span class="s2">&quot;running&quot;</span><span class="o">&gt;</span><span class="nx">Running</span><span class="o">&lt;</span><span class="err">/Select.Option&gt;</span>
</span><span id="__span-30-158"><a id="__codelineno-30-158" name="__codelineno-30-158" href="#__codelineno-30-158"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Select</span><span class="p">.</span><span class="nx">Option</span><span class="w"> </span><span class="nx">value</span><span class="o">=</span><span class="s2">&quot;completed&quot;</span><span class="o">&gt;</span><span class="nx">Completed</span><span class="o">&lt;</span><span class="err">/Select.Option&gt;</span>
</span><span id="__span-30-159"><a id="__codelineno-30-159" name="__codelineno-30-159" href="#__codelineno-30-159"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Select</span><span class="p">.</span><span class="nx">Option</span><span class="w"> </span><span class="nx">value</span><span class="o">=</span><span class="s2">&quot;failed&quot;</span><span class="o">&gt;</span><span class="nx">Failed</span><span class="o">&lt;</span><span class="err">/Select.Option&gt;</span>
</span><span id="__span-30-160"><a id="__codelineno-30-160" name="__codelineno-30-160" href="#__codelineno-30-160"></a><span class="w"> </span><span class="o">&lt;</span><span class="err">/Select&gt;</span>
</span><span id="__span-30-161"><a id="__codelineno-30-161" name="__codelineno-30-161" href="#__codelineno-30-161"></a>
</span><span id="__span-30-162"><a id="__codelineno-30-162" name="__codelineno-30-162" href="#__codelineno-30-162"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Select</span>
</span><span id="__span-30-163"><a id="__codelineno-30-163" name="__codelineno-30-163" href="#__codelineno-30-163"></a><span class="w"> </span><span class="nx">placeholder</span><span class="o">=</span><span class="s2">&quot;Filter by type&quot;</span>
</span><span id="__span-30-164"><a id="__codelineno-30-164" name="__codelineno-30-164" href="#__codelineno-30-164"></a><span class="w"> </span><span class="nx">style</span><span class="o">=</span><span class="p">{{</span><span class="w"> </span><span class="nx">width</span><span class="o">:</span><span class="w"> </span><span class="kt">200</span><span class="w"> </span><span class="p">}}</span>
</span><span id="__span-30-165"><a id="__codelineno-30-165" name="__codelineno-30-165" href="#__codelineno-30-165"></a><span class="w"> </span><span class="nx">onChange</span><span class="o">=</span><span class="p">{(</span><span class="nx">value</span><span class="p">)</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="nx">setFilter</span><span class="p">({</span><span class="w"> </span><span class="p">...</span><span class="nx">filter</span><span class="p">,</span><span class="w"> </span><span class="kr">type</span><span class="o">:</span><span class="w"> </span><span class="nx">value</span><span class="w"> </span><span class="p">})}</span>
</span><span id="__span-30-166"><a id="__codelineno-30-166" name="__codelineno-30-166" href="#__codelineno-30-166"></a><span class="w"> </span><span class="nx">allowClear</span>
</span><span id="__span-30-167"><a id="__codelineno-30-167" name="__codelineno-30-167" href="#__codelineno-30-167"></a><span class="w"> </span><span class="o">&gt;</span>
</span><span id="__span-30-168"><a id="__codelineno-30-168" name="__codelineno-30-168" href="#__codelineno-30-168"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Select</span><span class="p">.</span><span class="nx">Option</span><span class="w"> </span><span class="nx">value</span><span class="o">=</span><span class="s2">&quot;scan&quot;</span><span class="o">&gt;</span><span class="nx">Scan</span><span class="o">&lt;</span><span class="err">/Select.Option&gt;</span>
</span><span id="__span-30-169"><a id="__codelineno-30-169" name="__codelineno-30-169" href="#__codelineno-30-169"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Select</span><span class="p">.</span><span class="nx">Option</span><span class="w"> </span><span class="nx">value</span><span class="o">=</span><span class="s2">&quot;reencode_streaming&quot;</span><span class="o">&gt;</span><span class="nx">Re</span><span class="o">-</span><span class="nx">encode</span><span class="o">&lt;</span><span class="err">/Select.Option&gt;</span>
</span><span id="__span-30-170"><a id="__codelineno-30-170" name="__codelineno-30-170" href="#__codelineno-30-170"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Select</span><span class="p">.</span><span class="nx">Option</span><span class="w"> </span><span class="nx">value</span><span class="o">=</span><span class="s2">&quot;compile_random&quot;</span><span class="o">&gt;</span><span class="nx">Compilation</span><span class="o">&lt;</span><span class="err">/Select.Option&gt;</span>
</span><span id="__span-30-171"><a id="__codelineno-30-171" name="__codelineno-30-171" href="#__codelineno-30-171"></a><span class="w"> </span><span class="o">&lt;</span><span class="err">/Select&gt;</span>
</span><span id="__span-30-172"><a id="__codelineno-30-172" name="__codelineno-30-172" href="#__codelineno-30-172"></a>
</span><span id="__span-30-173"><a id="__codelineno-30-173" name="__codelineno-30-173" href="#__codelineno-30-173"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Button</span><span class="w"> </span><span class="nx">onClick</span><span class="o">=</span><span class="p">{()</span><span class="w"> </span><span class="p">=&gt;</span><span class="w"> </span><span class="nx">setPolling</span><span class="p">(</span><span class="o">!</span><span class="nx">polling</span><span class="p">)}</span><span class="o">&gt;</span>
</span><span id="__span-30-174"><a id="__codelineno-30-174" name="__codelineno-30-174" href="#__codelineno-30-174"></a><span class="w"> </span><span class="p">{</span><span class="nx">polling</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="s1">&#39;Stop Auto-Refresh&#39;</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;Start Auto-Refresh&#39;</span><span class="p">}</span>
</span><span id="__span-30-175"><a id="__codelineno-30-175" name="__codelineno-30-175" href="#__codelineno-30-175"></a><span class="w"> </span><span class="o">&lt;</span><span class="err">/Button&gt;</span>
</span><span id="__span-30-176"><a id="__codelineno-30-176" name="__codelineno-30-176" href="#__codelineno-30-176"></a><span class="w"> </span><span class="o">&lt;</span><span class="err">/Space&gt;</span>
</span><span id="__span-30-177"><a id="__codelineno-30-177" name="__codelineno-30-177" href="#__codelineno-30-177"></a>
</span><span id="__span-30-178"><a id="__codelineno-30-178" name="__codelineno-30-178" href="#__codelineno-30-178"></a><span class="w"> </span><span class="o">&lt;</span><span class="nx">Table</span>
</span><span id="__span-30-179"><a id="__codelineno-30-179" name="__codelineno-30-179" href="#__codelineno-30-179"></a><span class="w"> </span><span class="nx">columns</span><span class="o">=</span><span class="p">{</span><span class="nx">columns</span><span class="p">}</span>
</span><span id="__span-30-180"><a id="__codelineno-30-180" name="__codelineno-30-180" href="#__codelineno-30-180"></a><span class="w"> </span><span class="nx">dataSource</span><span class="o">=</span><span class="p">{</span><span class="nx">jobs</span><span class="p">}</span>
</span><span id="__span-30-181"><a id="__codelineno-30-181" name="__codelineno-30-181" href="#__codelineno-30-181"></a><span class="w"> </span><span class="nx">loading</span><span class="o">=</span><span class="p">{</span><span class="nx">loading</span><span class="p">}</span>
</span><span id="__span-30-182"><a id="__codelineno-30-182" name="__codelineno-30-182" href="#__codelineno-30-182"></a><span class="w"> </span><span class="nx">rowKey</span><span class="o">=</span><span class="s2">&quot;id&quot;</span>
</span><span id="__span-30-183"><a id="__codelineno-30-183" name="__codelineno-30-183" href="#__codelineno-30-183"></a><span class="w"> </span><span class="nx">pagination</span><span class="o">=</span><span class="p">{{</span><span class="w"> </span><span class="nx">pageSize</span><span class="o">:</span><span class="w"> </span><span class="kt">20</span><span class="w"> </span><span class="p">}}</span>
</span><span id="__span-30-184"><a id="__codelineno-30-184" name="__codelineno-30-184" href="#__codelineno-30-184"></a><span class="w"> </span><span class="o">/&gt;</span>
</span><span id="__span-30-185"><a id="__codelineno-30-185" name="__codelineno-30-185" href="#__codelineno-30-185"></a><span class="w"> </span><span class="o">&lt;</span><span class="err">/div&gt;</span>
</span><span id="__span-30-186"><a id="__codelineno-30-186" name="__codelineno-30-186" href="#__codelineno-30-186"></a><span class="w"> </span><span class="p">);</span>
</span><span id="__span-30-187"><a id="__codelineno-30-187" name="__codelineno-30-187" href="#__codelineno-30-187"></a><span class="p">}</span>
</span></code></pre></div>
<hr />
<h2 id="troubleshooting">Troubleshooting<a class="headerlink" href="#troubleshooting" title="Permanent link">&para;</a></h2>
<h3 id="problem-jobs-stuck-in-pending">Problem: Jobs Stuck in Pending<a class="headerlink" href="#problem-jobs-stuck-in-pending" title="Permanent link">&para;</a></h3>
<p><strong>Symptoms:</strong></p>
<ul>
<li>Jobs created but never start</li>
<li>Status remains "pending" for hours</li>
<li>No "running" jobs visible</li>
</ul>
<p><strong>Solutions:</strong></p>
<ol>
<li><strong>Check worker process running:</strong></li>
</ol>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-31-1"><a id="__codelineno-31-1" name="__codelineno-31-1" href="#__codelineno-31-1"></a>docker<span class="w"> </span>compose<span class="w"> </span>ps<span class="w"> </span>media-api
</span><span id="__span-31-2"><a id="__codelineno-31-2" name="__codelineno-31-2" href="#__codelineno-31-2"></a><span class="c1"># Should show &quot;Up&quot; status</span>
</span><span id="__span-31-3"><a id="__codelineno-31-3" name="__codelineno-31-3" href="#__codelineno-31-3"></a>
</span><span id="__span-31-4"><a id="__codelineno-31-4" name="__codelineno-31-4" href="#__codelineno-31-4"></a>docker<span class="w"> </span>compose<span class="w"> </span>logs<span class="w"> </span>media-api<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span><span class="s2">&quot;Job worker&quot;</span>
</span><span id="__span-31-5"><a id="__codelineno-31-5" name="__codelineno-31-5" href="#__codelineno-31-5"></a><span class="c1"># Should show &quot;Job worker started&quot;</span>
</span></code></pre></div>
<ol>
<li><strong>Manually trigger worker:</strong></li>
</ol>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-32-1"><a id="__codelineno-32-1" name="__codelineno-32-1" href="#__codelineno-32-1"></a><span class="c1"># Restart media-api container</span>
</span><span id="__span-32-2"><a id="__codelineno-32-2" name="__codelineno-32-2" href="#__codelineno-32-2"></a>docker<span class="w"> </span>compose<span class="w"> </span>restart<span class="w"> </span>media-api
</span><span id="__span-32-3"><a id="__codelineno-32-3" name="__codelineno-32-3" href="#__codelineno-32-3"></a>
</span><span id="__span-32-4"><a id="__codelineno-32-4" name="__codelineno-32-4" href="#__codelineno-32-4"></a><span class="c1"># Worker starts automatically on container boot</span>
</span></code></pre></div>
<ol>
<li><strong>Check worker logs for errors:</strong></li>
</ol>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-33-1"><a id="__codelineno-33-1" name="__codelineno-33-1" href="#__codelineno-33-1"></a>docker<span class="w"> </span>compose<span class="w"> </span>logs<span class="w"> </span>-f<span class="w"> </span>media-api<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>ERROR
</span><span id="__span-33-2"><a id="__codelineno-33-2" name="__codelineno-33-2" href="#__codelineno-33-2"></a><span class="c1"># Look for database connection errors, permission issues</span>
</span></code></pre></div>
<ol>
<li><strong>Verify database connection:</strong></li>
</ol>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-34-1"><a id="__codelineno-34-1" name="__codelineno-34-1" href="#__codelineno-34-1"></a><span class="c1"># Test database accessible from container</span>
</span><span id="__span-34-2"><a id="__codelineno-34-2" name="__codelineno-34-2" href="#__codelineno-34-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>media-api<span class="w"> </span>psql<span class="w"> </span><span class="nv">$DATABASE_URL</span><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;SELECT COUNT(*) FROM jobs WHERE status=&#39;pending&#39;;&quot;</span>
</span></code></pre></div>
<hr />
<h3 id="problem-job-fails-immediately">Problem: Job Fails Immediately<a class="headerlink" href="#problem-job-fails-immediately" title="Permanent link">&para;</a></h3>
<p><strong>Symptoms:</strong></p>
<ul>
<li>Job status changes from pending → running → failed within seconds</li>
<li>No meaningful progress</li>
<li>Error in log: "Command not found" or "Permission denied"</li>
</ul>
<p><strong>Solutions:</strong></p>
<ol>
<li><strong>Check job log in database:</strong></li>
</ol>
<div class="language-sql highlight"><pre><span></span><code><span id="__span-35-1"><a id="__codelineno-35-1" name="__codelineno-35-1" href="#__codelineno-35-1"></a><span class="k">SELECT</span><span class="w"> </span><span class="n">log</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">jobs</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="n">id</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">&#39;JOB_ID&#39;</span><span class="p">;</span>
</span></code></pre></div>
<ol>
<li><strong>Verify FFmpeg installed:</strong></li>
</ol>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-36-1"><a id="__codelineno-36-1" name="__codelineno-36-1" href="#__codelineno-36-1"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>media-api<span class="w"> </span>which<span class="w"> </span>ffmpeg
</span><span id="__span-36-2"><a id="__codelineno-36-2" name="__codelineno-36-2" href="#__codelineno-36-2"></a><span class="c1"># Should output: /usr/bin/ffmpeg</span>
</span><span id="__span-36-3"><a id="__codelineno-36-3" name="__codelineno-36-3" href="#__codelineno-36-3"></a>
</span><span id="__span-36-4"><a id="__codelineno-36-4" name="__codelineno-36-4" href="#__codelineno-36-4"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>media-api<span class="w"> </span>ffmpeg<span class="w"> </span>-version
</span></code></pre></div>
<ol>
<li><strong>Check file paths valid:</strong></li>
</ol>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-37-1"><a id="__codelineno-37-1" name="__codelineno-37-1" href="#__codelineno-37-1"></a><span class="c1"># Verify input file exists</span>
</span><span id="__span-37-2"><a id="__codelineno-37-2" name="__codelineno-37-2" href="#__codelineno-37-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>media-api<span class="w"> </span>ls<span class="w"> </span>-la<span class="w"> </span>/media/local/library/inbox/original.mp4
</span><span id="__span-37-3"><a id="__codelineno-37-3" name="__codelineno-37-3" href="#__codelineno-37-3"></a>
</span><span id="__span-37-4"><a id="__codelineno-37-4" name="__codelineno-37-4" href="#__codelineno-37-4"></a><span class="c1"># Check output directory writable</span>
</span><span id="__span-37-5"><a id="__codelineno-37-5" name="__codelineno-37-5" href="#__codelineno-37-5"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>media-api<span class="w"> </span>touch<span class="w"> </span>/media/local/playback/test.txt
</span></code></pre></div>
<ol>
<li><strong>Test FFmpeg command manually:</strong></li>
</ol>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-38-1"><a id="__codelineno-38-1" name="__codelineno-38-1" href="#__codelineno-38-1"></a><span class="c1"># Copy command from job log, run manually</span>
</span><span id="__span-38-2"><a id="__codelineno-38-2" name="__codelineno-38-2" href="#__codelineno-38-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>media-api<span class="w"> </span>ffmpeg<span class="w"> </span>-i<span class="w"> </span>/media/local/inbox/test.mp4<span class="w"> </span>-c:v<span class="w"> </span>libx264<span class="w"> </span>/media/local/playback/test-output.mp4
</span></code></pre></div>
<hr />
<h3 id="problem-re-encode-job-hangs-at-same-progress">Problem: Re-encode Job Hangs at Same Progress<a class="headerlink" href="#problem-re-encode-job-hangs-at-same-progress" title="Permanent link">&para;</a></h3>
<p><strong>Symptoms:</strong></p>
<ul>
<li>Job progress reaches 25%, 50%, or 75% then stops updating</li>
<li>Status remains "running" for hours</li>
<li>No CPU/GPU activity visible</li>
</ul>
<p><strong>Solutions:</strong></p>
<ol>
<li><strong>Check FFmpeg process still running:</strong></li>
</ol>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-39-1"><a id="__codelineno-39-1" name="__codelineno-39-1" href="#__codelineno-39-1"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>media-api<span class="w"> </span>ps<span class="w"> </span>aux<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>ffmpeg
</span><span id="__span-39-2"><a id="__codelineno-39-2" name="__codelineno-39-2" href="#__codelineno-39-2"></a><span class="c1"># Should show ffmpeg process</span>
</span><span id="__span-39-3"><a id="__codelineno-39-3" name="__codelineno-39-3" href="#__codelineno-39-3"></a>
</span><span id="__span-39-4"><a id="__codelineno-39-4" name="__codelineno-39-4" href="#__codelineno-39-4"></a><span class="c1"># If not running, worker crashed</span>
</span><span id="__span-39-5"><a id="__codelineno-39-5" name="__codelineno-39-5" href="#__codelineno-39-5"></a>docker<span class="w"> </span>compose<span class="w"> </span>logs<span class="w"> </span>media-api<span class="w"> </span>--tail<span class="w"> </span><span class="m">100</span>
</span></code></pre></div>
<ol>
<li><strong>Kill hung FFmpeg process:</strong></li>
</ol>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-40-1"><a id="__codelineno-40-1" name="__codelineno-40-1" href="#__codelineno-40-1"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>media-api<span class="w"> </span>pkill<span class="w"> </span>-9<span class="w"> </span>ffmpeg
</span><span id="__span-40-2"><a id="__codelineno-40-2" name="__codelineno-40-2" href="#__codelineno-40-2"></a>
</span><span id="__span-40-3"><a id="__codelineno-40-3" name="__codelineno-40-3" href="#__codelineno-40-3"></a><span class="c1"># Job will fail and can be retried</span>
</span></code></pre></div>
<ol>
<li><strong>Check disk space:</strong></li>
</ol>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-41-1"><a id="__codelineno-41-1" name="__codelineno-41-1" href="#__codelineno-41-1"></a>df<span class="w"> </span>-h<span class="w"> </span>/media/local/playback
</span><span id="__span-41-2"><a id="__codelineno-41-2" name="__codelineno-41-2" href="#__codelineno-41-2"></a><span class="c1"># If 100% full, encoding fails</span>
</span><span id="__span-41-3"><a id="__codelineno-41-3" name="__codelineno-41-3" href="#__codelineno-41-3"></a>
</span><span id="__span-41-4"><a id="__codelineno-41-4" name="__codelineno-41-4" href="#__codelineno-41-4"></a><span class="c1"># Free space</span>
</span><span id="__span-41-5"><a id="__codelineno-41-5" name="__codelineno-41-5" href="#__codelineno-41-5"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>media-api<span class="w"> </span>rm<span class="w"> </span>/media/local/playback/*.partial
</span></code></pre></div>
<ol>
<li><strong>Increase FFmpeg timeout (if very large file):</strong></li>
</ol>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-42-1"><a id="__codelineno-42-1" name="__codelineno-42-1" href="#__codelineno-42-1"></a><span class="c1">// api/src/modules/media/services/job-worker.service.ts</span>
</span><span id="__span-42-2"><a id="__codelineno-42-2" name="__codelineno-42-2" href="#__codelineno-42-2"></a><span class="kd">const</span><span class="w"> </span><span class="nx">FFMPEG_TIMEOUT</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">3600000</span><span class="p">;</span><span class="w"> </span><span class="c1">// 1 hour (from 30 minutes)</span>
</span></code></pre></div>
<hr />
<h3 id="problem-gpu-out-of-memory-errors">Problem: GPU Out of Memory Errors<a class="headerlink" href="#problem-gpu-out-of-memory-errors" title="Permanent link">&para;</a></h3>
<p><strong>Symptoms:</strong></p>
<ul>
<li>Multiple GPU jobs running simultaneously</li>
<li>Error in log: "CUDA out of memory" or "Cannot allocate memory"</li>
<li>System becomes unresponsive</li>
</ul>
<p><strong>Solutions:</strong></p>
<ol>
<li><strong>Check total VRAM available:</strong></li>
</ol>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-43-1"><a id="__codelineno-43-1" name="__codelineno-43-1" href="#__codelineno-43-1"></a>nvidia-smi
</span><span id="__span-43-2"><a id="__codelineno-43-2" name="__codelineno-43-2" href="#__codelineno-43-2"></a><span class="c1"># Shows GPU memory usage</span>
</span><span id="__span-43-3"><a id="__codelineno-43-3" name="__codelineno-43-3" href="#__codelineno-43-3"></a>
</span><span id="__span-43-4"><a id="__codelineno-43-4" name="__codelineno-43-4" href="#__codelineno-43-4"></a><span class="c1"># Should show &lt; 16GB used (adjust based on your GPU)</span>
</span></code></pre></div>
<ol>
<li><strong>Reduce concurrent GPU job limit:</strong></li>
</ol>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-44-1"><a id="__codelineno-44-1" name="__codelineno-44-1" href="#__codelineno-44-1"></a><span class="c1">// api/src/modules/media/services/job-worker.service.ts</span>
</span><span id="__span-44-2"><a id="__codelineno-44-2" name="__codelineno-44-2" href="#__codelineno-44-2"></a><span class="kd">const</span><span class="w"> </span><span class="nx">limits</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-44-3"><a id="__codelineno-44-3" name="__codelineno-44-3" href="#__codelineno-44-3"></a><span class="w"> </span><span class="nx">cpu</span><span class="o">:</span><span class="w"> </span><span class="kt">5</span><span class="p">,</span>
</span><span id="__span-44-4"><a id="__codelineno-44-4" name="__codelineno-44-4" href="#__codelineno-44-4"></a><span class="w"> </span><span class="nx">gpu_encode</span><span class="o">:</span><span class="w"> </span><span class="kt">1</span><span class="p">,</span><span class="w"> </span><span class="c1">// Reduced from 2</span>
</span><span id="__span-44-5"><a id="__codelineno-44-5" name="__codelineno-44-5" href="#__codelineno-44-5"></a><span class="w"> </span><span class="nx">gpu_ai</span><span class="o">:</span><span class="w"> </span><span class="kt">1</span><span class="p">,</span>
</span><span id="__span-44-6"><a id="__codelineno-44-6" name="__codelineno-44-6" href="#__codelineno-44-6"></a><span class="p">};</span>
</span></code></pre></div>
<ol>
<li><strong>Increase VRAM requirements for jobs:</strong></li>
</ol>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-45-1"><a id="__codelineno-45-1" name="__codelineno-45-1" href="#__codelineno-45-1"></a><span class="c1">// Jobs require more VRAM than specified</span>
</span><span id="__span-45-2"><a id="__codelineno-45-2" name="__codelineno-45-2" href="#__codelineno-45-2"></a><span class="c1">// Update job creation to use higher vramRequired values</span>
</span><span id="__span-45-3"><a id="__codelineno-45-3" name="__codelineno-45-3" href="#__codelineno-45-3"></a><span class="p">{</span>
</span><span id="__span-45-4"><a id="__codelineno-45-4" name="__codelineno-45-4" href="#__codelineno-45-4"></a><span class="w"> </span><span class="kr">type</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;reencode_streaming&#39;</span><span class="p">,</span>
</span><span id="__span-45-5"><a id="__codelineno-45-5" name="__codelineno-45-5" href="#__codelineno-45-5"></a><span class="w"> </span><span class="nx">vramRequired</span><span class="o">:</span><span class="w"> </span><span class="kt">6000</span><span class="p">,</span><span class="w"> </span><span class="c1">// Increased from 4000</span>
</span><span id="__span-45-6"><a id="__codelineno-45-6" name="__codelineno-45-6" href="#__codelineno-45-6"></a><span class="p">}</span>
</span></code></pre></div>
<ol>
<li><strong>Kill running GPU jobs:</strong></li>
</ol>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-46-1"><a id="__codelineno-46-1" name="__codelineno-46-1" href="#__codelineno-46-1"></a><span class="c1"># Stop all media jobs</span>
</span><span id="__span-46-2"><a id="__codelineno-46-2" name="__codelineno-46-2" href="#__codelineno-46-2"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>media-api<span class="w"> </span>pkill<span class="w"> </span>-9<span class="w"> </span>ffmpeg
</span><span id="__span-46-3"><a id="__codelineno-46-3" name="__codelineno-46-3" href="#__codelineno-46-3"></a>
</span><span id="__span-46-4"><a id="__codelineno-46-4" name="__codelineno-46-4" href="#__codelineno-46-4"></a><span class="c1"># Update stuck jobs to failed status</span>
</span><span id="__span-46-5"><a id="__codelineno-46-5" name="__codelineno-46-5" href="#__codelineno-46-5"></a>docker<span class="w"> </span>compose<span class="w"> </span><span class="nb">exec</span><span class="w"> </span>v2-postgres<span class="w"> </span>psql<span class="w"> </span>-U<span class="w"> </span>changemaker<span class="w"> </span>-d<span class="w"> </span>v2_changemaker<span class="w"> </span><span class="se">\</span>
</span><span id="__span-46-6"><a id="__codelineno-46-6" name="__codelineno-46-6" href="#__codelineno-46-6"></a><span class="w"> </span>-c<span class="w"> </span><span class="s2">&quot;UPDATE jobs SET status=&#39;failed&#39; WHERE status=&#39;running&#39;;&quot;</span>
</span></code></pre></div>
<hr />
<h2 id="performance-considerations">Performance Considerations<a class="headerlink" href="#performance-considerations" title="Permanent link">&para;</a></h2>
<h3 id="job-queue-throughput">Job Queue Throughput<a class="headerlink" href="#job-queue-throughput" title="Permanent link">&para;</a></h3>
<p><strong>Scaling Factors:</strong></p>
<ul>
<li>CPU jobs: 5 concurrent = ~10-20 jobs/minute (scans, validations)</li>
<li>GPU encode: 2 concurrent = ~4-8 videos/hour (depends on length)</li>
<li>GPU AI: 1 concurrent = ~2-6 videos/hour (depends on complexity)</li>
</ul>
<p><strong>Bottlenecks:</strong></p>
<ol>
<li><strong>GPU Memory</strong> — Limits concurrent GPU jobs</li>
<li><strong>Disk I/O</strong> — Reading/writing large video files</li>
<li><strong>CPU</strong> — FFmpeg encoding uses all available cores</li>
</ol>
<p><strong>Optimization:</strong></p>
<ul>
<li><strong>Distribute workers across multiple machines</strong> — Each machine runs separate worker process</li>
<li><strong>Use job priority</strong> — Urgent jobs (priority 1-3) run first</li>
<li><strong>Batch similar jobs</strong> — Group scan jobs, re-encode jobs, etc. for efficiency</li>
</ul>
<hr />
<h3 id="database-performance">Database Performance<a class="headerlink" href="#database-performance" title="Permanent link">&para;</a></h3>
<p><strong>Job Queue Index:</strong></p>
<div class="language-sql highlight"><pre><span></span><code><span id="__span-47-1"><a id="__codelineno-47-1" name="__codelineno-47-1" href="#__codelineno-47-1"></a><span class="k">CREATE</span><span class="w"> </span><span class="k">INDEX</span><span class="w"> </span><span class="n">idx_jobs_status_priority</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">jobs</span><span class="p">(</span><span class="n">status</span><span class="p">,</span><span class="w"> </span><span class="n">priority</span><span class="p">,</span><span class="w"> </span><span class="n">created_at</span><span class="p">);</span>
</span></code></pre></div>
<p><strong>Query Performance:</strong></p>
<ul>
<li>Find next pending job: ~1-5ms (with index)</li>
<li>Update job status: ~2-10ms</li>
<li>Fetch job logs: ~5-20ms</li>
</ul>
<p><strong>Optimization:</strong></p>
<ul>
<li><strong>Partition jobs table by date</strong> — Move old completed/failed jobs to archive table</li>
<li><strong>Limit log size</strong> — Truncate logs &gt; 10KB to prevent bloat</li>
</ul>
<hr />
<h2 id="monitoring-observability">Monitoring &amp; Observability<a class="headerlink" href="#monitoring-observability" title="Permanent link">&para;</a></h2>
<h3 id="prometheus-metrics">Prometheus Metrics<a class="headerlink" href="#prometheus-metrics" title="Permanent link">&para;</a></h3>
<div class="language-typescript highlight"><pre><span></span><code><span id="__span-48-1"><a id="__codelineno-48-1" name="__codelineno-48-1" href="#__codelineno-48-1"></a><span class="c1">// api/src/utils/metrics.ts</span>
</span><span id="__span-48-2"><a id="__codelineno-48-2" name="__codelineno-48-2" href="#__codelineno-48-2"></a><span class="k">import</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">Counter</span><span class="p">,</span><span class="w"> </span><span class="nx">Gauge</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="kr">from</span><span class="w"> </span><span class="s1">&#39;prom-client&#39;</span><span class="p">;</span>
</span><span id="__span-48-3"><a id="__codelineno-48-3" name="__codelineno-48-3" href="#__codelineno-48-3"></a>
</span><span id="__span-48-4"><a id="__codelineno-48-4" name="__codelineno-48-4" href="#__codelineno-48-4"></a><span class="k">export</span><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">mediaJobsTotal</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nx">Counter</span><span class="p">({</span>
</span><span id="__span-48-5"><a id="__codelineno-48-5" name="__codelineno-48-5" href="#__codelineno-48-5"></a><span class="w"> </span><span class="nx">name</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;media_jobs_total&#39;</span><span class="p">,</span>
</span><span id="__span-48-6"><a id="__codelineno-48-6" name="__codelineno-48-6" href="#__codelineno-48-6"></a><span class="w"> </span><span class="nx">help</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;Total media jobs created&#39;</span><span class="p">,</span>
</span><span id="__span-48-7"><a id="__codelineno-48-7" name="__codelineno-48-7" href="#__codelineno-48-7"></a><span class="w"> </span><span class="nx">labelNames</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="s1">&#39;type&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;status&#39;</span><span class="p">],</span>
</span><span id="__span-48-8"><a id="__codelineno-48-8" name="__codelineno-48-8" href="#__codelineno-48-8"></a><span class="p">});</span>
</span><span id="__span-48-9"><a id="__codelineno-48-9" name="__codelineno-48-9" href="#__codelineno-48-9"></a>
</span><span id="__span-48-10"><a id="__codelineno-48-10" name="__codelineno-48-10" href="#__codelineno-48-10"></a><span class="k">export</span><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">mediaJobsPending</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nx">Gauge</span><span class="p">({</span>
</span><span id="__span-48-11"><a id="__codelineno-48-11" name="__codelineno-48-11" href="#__codelineno-48-11"></a><span class="w"> </span><span class="nx">name</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;media_jobs_pending&#39;</span><span class="p">,</span>
</span><span id="__span-48-12"><a id="__codelineno-48-12" name="__codelineno-48-12" href="#__codelineno-48-12"></a><span class="w"> </span><span class="nx">help</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;Number of pending media jobs&#39;</span><span class="p">,</span>
</span><span id="__span-48-13"><a id="__codelineno-48-13" name="__codelineno-48-13" href="#__codelineno-48-13"></a><span class="p">});</span>
</span><span id="__span-48-14"><a id="__codelineno-48-14" name="__codelineno-48-14" href="#__codelineno-48-14"></a>
</span><span id="__span-48-15"><a id="__codelineno-48-15" name="__codelineno-48-15" href="#__codelineno-48-15"></a><span class="k">export</span><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">mediaJobsRunning</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nx">Gauge</span><span class="p">({</span>
</span><span id="__span-48-16"><a id="__codelineno-48-16" name="__codelineno-48-16" href="#__codelineno-48-16"></a><span class="w"> </span><span class="nx">name</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;media_jobs_running&#39;</span><span class="p">,</span>
</span><span id="__span-48-17"><a id="__codelineno-48-17" name="__codelineno-48-17" href="#__codelineno-48-17"></a><span class="w"> </span><span class="nx">help</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;Number of running media jobs&#39;</span><span class="p">,</span>
</span><span id="__span-48-18"><a id="__codelineno-48-18" name="__codelineno-48-18" href="#__codelineno-48-18"></a><span class="w"> </span><span class="nx">labelNames</span><span class="o">:</span><span class="w"> </span><span class="p">[</span><span class="s1">&#39;resourceCategory&#39;</span><span class="p">],</span>
</span><span id="__span-48-19"><a id="__codelineno-48-19" name="__codelineno-48-19" href="#__codelineno-48-19"></a><span class="p">});</span>
</span><span id="__span-48-20"><a id="__codelineno-48-20" name="__codelineno-48-20" href="#__codelineno-48-20"></a>
</span><span id="__span-48-21"><a id="__codelineno-48-21" name="__codelineno-48-21" href="#__codelineno-48-21"></a><span class="k">export</span><span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">mediaVramUsed</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nx">Gauge</span><span class="p">({</span>
</span><span id="__span-48-22"><a id="__codelineno-48-22" name="__codelineno-48-22" href="#__codelineno-48-22"></a><span class="w"> </span><span class="nx">name</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;media_vram_used_mb&#39;</span><span class="p">,</span>
</span><span id="__span-48-23"><a id="__codelineno-48-23" name="__codelineno-48-23" href="#__codelineno-48-23"></a><span class="w"> </span><span class="nx">help</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;Total VRAM used by running jobs (MB)&#39;</span><span class="p">,</span>
</span><span id="__span-48-24"><a id="__codelineno-48-24" name="__codelineno-48-24" href="#__codelineno-48-24"></a><span class="p">});</span>
</span><span id="__span-48-25"><a id="__codelineno-48-25" name="__codelineno-48-25" href="#__codelineno-48-25"></a>
</span><span id="__span-48-26"><a id="__codelineno-48-26" name="__codelineno-48-26" href="#__codelineno-48-26"></a><span class="c1">// Update metrics in worker</span>
</span><span id="__span-48-27"><a id="__codelineno-48-27" name="__codelineno-48-27" href="#__codelineno-48-27"></a><span class="nx">mediaJobsPending</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="nx">pendingCount</span><span class="p">);</span>
</span><span id="__span-48-28"><a id="__codelineno-48-28" name="__codelineno-48-28" href="#__codelineno-48-28"></a><span class="nx">mediaJobsRunning</span><span class="p">.</span><span class="nx">set</span><span class="p">({</span><span class="w"> </span><span class="nx">resourceCategory</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;gpu_encode&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="nx">gpuEncodeCount</span><span class="p">);</span>
</span><span id="__span-48-29"><a id="__codelineno-48-29" name="__codelineno-48-29" href="#__codelineno-48-29"></a><span class="nx">mediaVramUsed</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="nx">totalVramUsed</span><span class="p">);</span>
</span></code></pre></div>
<h3 id="grafana-dashboard-panel">Grafana Dashboard Panel<a class="headerlink" href="#grafana-dashboard-panel" title="Permanent link">&para;</a></h3>
<p><strong>Job Queue Status:</strong></p>
<div class="language-promql highlight"><pre><span></span><code><span id="__span-49-1"><a id="__codelineno-49-1" name="__codelineno-49-1" href="#__codelineno-49-1"></a><span class="c1"># Pending jobs count</span>
</span><span id="__span-49-2"><a id="__codelineno-49-2" name="__codelineno-49-2" href="#__codelineno-49-2"></a><span class="nv">media_jobs_pending</span>
</span><span id="__span-49-3"><a id="__codelineno-49-3" name="__codelineno-49-3" href="#__codelineno-49-3"></a>
</span><span id="__span-49-4"><a id="__codelineno-49-4" name="__codelineno-49-4" href="#__codelineno-49-4"></a><span class="c1"># Running jobs by category</span>
</span><span id="__span-49-5"><a id="__codelineno-49-5" name="__codelineno-49-5" href="#__codelineno-49-5"></a><span class="k">sum</span><span class="o">(</span><span class="nv">media_jobs_running</span><span class="o">)</span><span class="w"> </span><span class="k">by</span><span class="w"> </span><span class="o">(</span><span class="nv">resourceCategory</span><span class="o">)</span>
</span><span id="__span-49-6"><a id="__codelineno-49-6" name="__codelineno-49-6" href="#__codelineno-49-6"></a>
</span><span id="__span-49-7"><a id="__codelineno-49-7" name="__codelineno-49-7" href="#__codelineno-49-7"></a><span class="c1"># VRAM usage percentage</span>
</span><span id="__span-49-8"><a id="__codelineno-49-8" name="__codelineno-49-8" href="#__codelineno-49-8"></a><span class="o">(</span><span class="nv">media_vram_used_mb</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">16000</span><span class="o">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">100</span>
</span></code></pre></div>
<p><strong>Alert Rules:</strong></p>
<div class="language-yaml highlight"><pre><span></span><code><span id="__span-50-1"><a id="__codelineno-50-1" name="__codelineno-50-1" href="#__codelineno-50-1"></a><span class="c1"># configs/prometheus/alerts.yml</span>
</span><span id="__span-50-2"><a id="__codelineno-50-2" name="__codelineno-50-2" href="#__codelineno-50-2"></a><span class="nt">groups</span><span class="p">:</span>
</span><span id="__span-50-3"><a id="__codelineno-50-3" name="__codelineno-50-3" href="#__codelineno-50-3"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">media_jobs</span>
</span><span id="__span-50-4"><a id="__codelineno-50-4" name="__codelineno-50-4" href="#__codelineno-50-4"></a><span class="w"> </span><span class="nt">rules</span><span class="p">:</span>
</span><span id="__span-50-5"><a id="__codelineno-50-5" name="__codelineno-50-5" href="#__codelineno-50-5"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">alert</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">MediaJobQueueBacklog</span>
</span><span id="__span-50-6"><a id="__codelineno-50-6" name="__codelineno-50-6" href="#__codelineno-50-6"></a><span class="w"> </span><span class="nt">expr</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">media_jobs_pending &gt; 50</span>
</span><span id="__span-50-7"><a id="__codelineno-50-7" name="__codelineno-50-7" href="#__codelineno-50-7"></a><span class="w"> </span><span class="nt">for</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">30m</span>
</span><span id="__span-50-8"><a id="__codelineno-50-8" name="__codelineno-50-8" href="#__codelineno-50-8"></a><span class="w"> </span><span class="nt">labels</span><span class="p">:</span>
</span><span id="__span-50-9"><a id="__codelineno-50-9" name="__codelineno-50-9" href="#__codelineno-50-9"></a><span class="w"> </span><span class="nt">severity</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">warning</span>
</span><span id="__span-50-10"><a id="__codelineno-50-10" name="__codelineno-50-10" href="#__codelineno-50-10"></a><span class="w"> </span><span class="nt">annotations</span><span class="p">:</span>
</span><span id="__span-50-11"><a id="__codelineno-50-11" name="__codelineno-50-11" href="#__codelineno-50-11"></a><span class="w"> </span><span class="nt">summary</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;Media</span><span class="nv"> </span><span class="s">job</span><span class="nv"> </span><span class="s">queue</span><span class="nv"> </span><span class="s">backlog&quot;</span>
</span><span id="__span-50-12"><a id="__codelineno-50-12" name="__codelineno-50-12" href="#__codelineno-50-12"></a><span class="w"> </span><span class="nt">description</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;{{</span><span class="nv"> </span><span class="s">$value</span><span class="nv"> </span><span class="s">}}</span><span class="nv"> </span><span class="s">jobs</span><span class="nv"> </span><span class="s">pending</span><span class="nv"> </span><span class="s">for</span><span class="nv"> </span><span class="s">30+</span><span class="nv"> </span><span class="s">minutes&quot;</span>
</span><span id="__span-50-13"><a id="__codelineno-50-13" name="__codelineno-50-13" href="#__codelineno-50-13"></a>
</span><span id="__span-50-14"><a id="__codelineno-50-14" name="__codelineno-50-14" href="#__codelineno-50-14"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">alert</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">MediaJobsStuckRunning</span>
</span><span id="__span-50-15"><a id="__codelineno-50-15" name="__codelineno-50-15" href="#__codelineno-50-15"></a><span class="w"> </span><span class="nt">expr</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">sum(media_jobs_running) == 0 AND media_jobs_pending &gt; 0</span>
</span><span id="__span-50-16"><a id="__codelineno-50-16" name="__codelineno-50-16" href="#__codelineno-50-16"></a><span class="w"> </span><span class="nt">for</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">10m</span>
</span><span id="__span-50-17"><a id="__codelineno-50-17" name="__codelineno-50-17" href="#__codelineno-50-17"></a><span class="w"> </span><span class="nt">labels</span><span class="p">:</span>
</span><span id="__span-50-18"><a id="__codelineno-50-18" name="__codelineno-50-18" href="#__codelineno-50-18"></a><span class="w"> </span><span class="nt">severity</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">critical</span>
</span><span id="__span-50-19"><a id="__codelineno-50-19" name="__codelineno-50-19" href="#__codelineno-50-19"></a><span class="w"> </span><span class="nt">annotations</span><span class="p">:</span>
</span><span id="__span-50-20"><a id="__codelineno-50-20" name="__codelineno-50-20" href="#__codelineno-50-20"></a><span class="w"> </span><span class="nt">summary</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;Media</span><span class="nv"> </span><span class="s">jobs</span><span class="nv"> </span><span class="s">stuck&quot;</span>
</span><span id="__span-50-21"><a id="__codelineno-50-21" name="__codelineno-50-21" href="#__codelineno-50-21"></a><span class="w"> </span><span class="nt">description</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;Jobs</span><span class="nv"> </span><span class="s">pending</span><span class="nv"> </span><span class="s">but</span><span class="nv"> </span><span class="s">worker</span><span class="nv"> </span><span class="s">not</span><span class="nv"> </span><span class="s">processing&quot;</span>
</span></code></pre></div>
<hr />
<h2 id="related-documentation">Related Documentation<a class="headerlink" href="#related-documentation" title="Permanent link">&para;</a></h2>
<h3 id="backend-documentation">Backend Documentation<a class="headerlink" href="#backend-documentation" title="Permanent link">&para;</a></h3>
<ul>
<li><strong>Job Worker:</strong> <code>backend/modules/media/job-worker.md</code> — Worker process implementation</li>
<li><strong>Job Processors:</strong> <code>backend/modules/media/processors/</code> — Individual job type processors (reencode, scan, etc.)</li>
<li><strong>Jobs Routes:</strong> <code>backend/modules/media/jobs.md</code> — API endpoints for job management</li>
</ul>
<h3 id="frontend-documentation">Frontend Documentation<a class="headerlink" href="#frontend-documentation" title="Permanent link">&para;</a></h3>
<ul>
<li><strong>Jobs Page:</strong> <code>frontend/pages/media/jobs.md</code> — Job queue monitoring UI</li>
<li><strong>Job Detail Modal:</strong> <code>frontend/components/media/job-detail.md</code> — Log viewer component</li>
</ul>
<h3 id="feature-documentation">Feature Documentation<a class="headerlink" href="#feature-documentation" title="Permanent link">&para;</a></h3>
<ul>
<li><strong>Video Library:</strong> <code>features/media/video-library.md</code> — Triggering jobs from library actions</li>
<li><strong>Upload System:</strong> <code>features/media/upload.md</code> — Post-upload job creation</li>
</ul>
<hr />
<h2 id="next-steps">Next Steps<a class="headerlink" href="#next-steps" title="Permanent link">&para;</a></h2>
<p>After mastering the job queue:</p>
<ol>
<li><strong>Create Custom Jobs</strong> — Implement new job types for domain-specific processing</li>
<li><strong>Optimize Scheduling</strong> — Tune resource limits and priority settings for your workload</li>
<li><strong>Monitor Performance</strong> — Set up Grafana dashboards and alerts for job queue health</li>
<li><strong>Distributed Workers</strong> — Scale horizontally by running workers on multiple machines</li>
</ol>
<p><strong>Hands-On Practice:</strong></p>
<div class="language-bash highlight"><pre><span></span><code><span id="__span-51-1"><a id="__codelineno-51-1" name="__codelineno-51-1" href="#__codelineno-51-1"></a><span class="c1"># 1. Create re-encode job</span>
</span><span id="__span-51-2"><a id="__codelineno-51-2" name="__codelineno-51-2" href="#__codelineno-51-2"></a>curl<span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span>http://localhost:4100/api/media/jobs<span class="w"> </span><span class="se">\</span>
</span><span id="__span-51-3"><a id="__codelineno-51-3" name="__codelineno-51-3" href="#__codelineno-51-3"></a><span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;Authorization: Bearer YOUR_TOKEN&quot;</span><span class="w"> </span><span class="se">\</span>
</span><span id="__span-51-4"><a id="__codelineno-51-4" name="__codelineno-51-4" href="#__codelineno-51-4"></a><span class="w"> </span>-H<span class="w"> </span><span class="s2">&quot;Content-Type: application/json&quot;</span><span class="w"> </span><span class="se">\</span>
</span><span id="__span-51-5"><a id="__codelineno-51-5" name="__codelineno-51-5" href="#__codelineno-51-5"></a><span class="w"> </span>-d<span class="w"> </span><span class="s1">&#39;{</span>
</span><span id="__span-51-6"><a id="__codelineno-51-6" name="__codelineno-51-6" href="#__codelineno-51-6"></a><span class="s1"> &quot;type&quot;: &quot;reencode_streaming&quot;,</span>
</span><span id="__span-51-7"><a id="__codelineno-51-7" name="__codelineno-51-7" href="#__codelineno-51-7"></a><span class="s1"> &quot;params&quot;: { &quot;videoId&quot;: &quot;VIDEO_ID&quot;, &quot;targetBitrate&quot;: 2000 },</span>
</span><span id="__span-51-8"><a id="__codelineno-51-8" name="__codelineno-51-8" href="#__codelineno-51-8"></a><span class="s1"> &quot;priority&quot;: 5</span>
</span><span id="__span-51-9"><a id="__codelineno-51-9" name="__codelineno-51-9" href="#__codelineno-51-9"></a><span class="s1"> }&#39;</span>
</span><span id="__span-51-10"><a id="__codelineno-51-10" name="__codelineno-51-10" href="#__codelineno-51-10"></a>
</span><span id="__span-51-11"><a id="__codelineno-51-11" name="__codelineno-51-11" href="#__codelineno-51-11"></a><span class="c1"># 2. Monitor job progress</span>
</span><span id="__span-51-12"><a id="__codelineno-51-12" name="__codelineno-51-12" href="#__codelineno-51-12"></a>watch<span class="w"> </span>-n<span class="w"> </span><span class="m">2</span><span class="w"> </span><span class="s1">&#39;curl -s http://localhost:4100/api/media/jobs/JOB_ID | jq &quot;.progress&quot;&#39;</span>
</span><span id="__span-51-13"><a id="__codelineno-51-13" name="__codelineno-51-13" href="#__codelineno-51-13"></a>
</span><span id="__span-51-14"><a id="__codelineno-51-14" name="__codelineno-51-14" href="#__codelineno-51-14"></a><span class="c1"># 3. View job logs</span>
</span><span id="__span-51-15"><a id="__codelineno-51-15" name="__codelineno-51-15" href="#__codelineno-51-15"></a>curl<span class="w"> </span>http://localhost:4100/api/media/jobs/JOB_ID<span class="w"> </span><span class="p">|</span><span class="w"> </span>jq<span class="w"> </span>-r<span class="w"> </span><span class="s2">&quot;.log&quot;</span>
</span><span id="__span-51-16"><a id="__codelineno-51-16" name="__codelineno-51-16" href="#__codelineno-51-16"></a>
</span><span id="__span-51-17"><a id="__codelineno-51-17" name="__codelineno-51-17" href="#__codelineno-51-17"></a><span class="c1"># 4. Check queue stats</span>
</span><span id="__span-51-18"><a id="__codelineno-51-18" name="__codelineno-51-18" href="#__codelineno-51-18"></a>curl<span class="w"> </span>http://localhost:4100/api/media/jobs/stats<span class="w"> </span><span class="p">|</span><span class="w"> </span>jq
</span></code></pre></div>
<hr />
<p><strong>Last Updated:</strong> 2026-02-13
<strong>Version:</strong> V2.0
<strong>Maintainer:</strong> Changemaker Lite Team</p>
</article>
</div>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg>
Back to top
</button>
</main>
<footer class="md-footer">
<nav class="md-footer__inner md-grid" aria-label="Footer" >
<a href="../public-gallery/" class="md-footer__link md-footer__link--prev" aria-label="Previous: Public Gallery">
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</div>
<div class="md-footer__title">
<span class="md-footer__direction">
Previous
</span>
<div class="md-ellipsis">
Public Gallery
</div>
</div>
</a>
<a href="../../newsletter/" class="md-footer__link md-footer__link--next" aria-label="Next: Newsletter Integration (Listmonk)">
<div class="md-footer__title">
<span class="md-footer__direction">
Next
</span>
<div class="md-ellipsis">
Newsletter Integration (Listmonk)
</div>
</div>
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11z"/></svg>
</div>
</a>
</nav>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
<div class="md-copyright__highlight">
Copyright &copy; 2024 The Bunker Operations <a href="#__consent">Change cookie settings</a>
</div>
</div>
<div class="md-social">
<a href="https://gitea.bnkops.com/admin" target="_blank" rel="noopener" title="Gitea Repository" class="md-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M173.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M252.8 8C114.1 8 8 113.3 8 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C436.2 457.8 504 362.9 504 252 504 113.3 391.5 8 252.8 8M105.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg>
</a>
<a href="https://listmonk.bnkops.com/subscription/form" target="_blank" rel="noopener" title="Newsletter" class="md-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M536.4-26.3c9.8-3.5 20.6-1 28 6.3s9.8 18.2 6.3 28l-178 496.9c-5 13.9-18.1 23.1-32.8 23.1-14.2 0-27-8.6-32.3-21.7l-64.2-158c-4.5-11-2.5-23.6 5.2-32.6l94.5-112.4c5.1-6.1 4.7-15-.9-20.6s-14.6-6-20.6-.9l-112.4 94.3c-9.1 7.6-21.6 9.6-32.6 5.2L38.1 216.8c-13.1-5.3-21.7-18.1-21.7-32.3 0-14.7 9.2-27.8 23.1-32.8z"/></svg>
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"annotate": null, "base": "../../../..", "features": ["announce.dismiss", "content.action.edit", "content.action.view", "content.code.annotate", "content.code.copy", "content.tooltips", "navigation.expand", "navigation.footer", "navigation.indexes", "navigation.path", "navigation.prune", "navigation.sections", "navigation.tabs", "navigation.tabs.sticky", "navigation.top", "navigation.tracking", "search.highlight", "search.share", "search.suggest", "toc.follow"], "search": "../../../../assets/javascripts/workers/search.2c215733.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
<script src="../../../../assets/javascripts/bundle.79ae519e.min.js"></script>
<script src="../../../../javascripts/home.js"></script>
<script src="../../../../javascripts/github-widget.js"></script>
<script src="../../../../javascripts/gitea-widget.js"></script>
<script src="../../../../assets/js/env-config.js"></script>
<script src="../../../../assets/js/video-player.js"></script>
</body>
</html>