32 lines
1.4 KiB
Python
32 lines
1.4 KiB
Python
"""
|
|
Minimal in-process background job dispatcher for long-running admin jobs
|
|
(catalog ingestion, store seeding, ML model training, nutrition
|
|
enrichment).
|
|
|
|
This deliberately does NOT use Starlette's `BackgroundTasks`. BackgroundTasks
|
|
run *synchronously after the response is sent*: an async background task is
|
|
awaited directly on the server's event loop, and a sync one is awaited in the
|
|
request's thread. Either way the request handler does not return until the job
|
|
finishes. For jobs that take minutes (LLM calls, web scraping, ML training,
|
|
Open Food Facts lookups), that turns a "kick off a job and return 202" endpoint
|
|
into a blocking call and, for async tasks, freezes the whole API event loop for
|
|
the duration.
|
|
|
|
A daemon thread returns control to the caller immediately, and the job's
|
|
progress stays visible via the job_store polling endpoints the UI already
|
|
uses. Daemon threads are a deliberate, documented trade-off (see
|
|
`app/api/job_store.py`): state is process-local and not safe across multiple
|
|
uvicorn workers - fine for this project's intended single-process, CPU-only
|
|
deployment.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import threading
|
|
from typing import Any, Callable
|
|
|
|
|
|
def run_in_background(func: Callable[[], Any], *, name: str) -> None:
|
|
"""Start `func` on a new daemon thread and return immediately."""
|
|
thread = threading.Thread(target=func, name=name, daemon=True)
|
|
thread.start()
|