Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
36 lines
1.2 KiB
Python
36 lines
1.2 KiB
Python
"""Background jobs (final render, combined export): ffmpeg can outlast a tunnel's request
|
|
timeout, so the request returns an id and the page polls for it."""
|
|
|
|
import asyncio
|
|
import uuid
|
|
from collections import OrderedDict
|
|
|
|
MAX_JOBS = 50 # finished jobs are kept this long for the poll that reads them
|
|
|
|
_jobs: "OrderedDict[str, dict]" = OrderedDict()
|
|
|
|
|
|
def new() -> str:
|
|
job = uuid.uuid4().hex
|
|
_jobs[job] = {"state": "queued"}
|
|
while len(_jobs) > MAX_JOBS:
|
|
_jobs.popitem(last=False)
|
|
return job
|
|
|
|
|
|
def get(job: str) -> dict | None:
|
|
return _jobs.get(job)
|
|
|
|
|
|
async def run(job: str, fn, *args, error) -> None:
|
|
"""Run the blocking `fn(*args)` off the event loop and record how it ended. `error` is the
|
|
exception class whose message is meant for the person; anything else is reported plainly."""
|
|
_jobs[job] = {"state": "running"}
|
|
try:
|
|
result = await asyncio.to_thread(fn, *args)
|
|
_jobs[job] = {"state": "done", **result}
|
|
except error as exc:
|
|
_jobs[job] = {"state": "error", "detail": str(exc)}
|
|
except Exception as exc: # noqa: BLE001
|
|
_jobs[job] = {"state": "error", "detail": f"{type(exc).__name__}: {exc}"}
|