Spaces:
Sleeping
Sleeping
File size: 1,671 Bytes
0136798 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | """Queue document ingestion with a concurrency limit so large batches do not overwhelm the server.
For batch uploads of thousands of files, tasks queue behind the semaphore and
execute as slots free up — the server stays responsive for status polls and new
requests throughout.
"""
import asyncio
import logging
from pathlib import Path
from app.config import settings
logger = logging.getLogger(__name__)
_background_tasks: set[asyncio.Task] = set() # type: ignore[type-arg]
_sem: asyncio.Semaphore | None = None
def _ingest_semaphore() -> asyncio.Semaphore:
global _sem
if _sem is None:
_sem = asyncio.Semaphore(max(1, settings.max_concurrent_ingests))
return _sem
async def _ingest_worker(doc_id: str, file_path: Path) -> None:
async with _ingest_semaphore():
from app.ingest import pipeline
await pipeline.ingest_document(doc_id=doc_id, file_path=file_path)
def schedule_ingest(doc_id: str, file_path: Path) -> None:
"""Fire-and-forget background ingestion for a committed Document row."""
task = asyncio.create_task(_ingest_worker(doc_id, file_path))
_background_tasks.add(task)
def _done(t: asyncio.Task) -> None: # type: ignore[type-arg]
_background_tasks.discard(t)
try:
t.result()
except Exception:
logger.exception("Background ingest task failed doc_id=%s", doc_id)
task.add_done_callback(_done)
logger.info("Queued ingestion doc=%s path=%s (queue_size=%d)", doc_id, file_path, len(_background_tasks))
def pending_count() -> int:
"""How many ingest tasks are currently queued or running."""
return len(_background_tasks)
|