Skip to Content

How do you run async-only Python from a synchronous Celery worker?

Category: Backend & API

Answer

Celery workers are sync by design. To call an async def function from a Celery task, bridge it with asyncio.run() if no loop exists, or grab the existing loop if you’re already in one. The pattern lets you reuse the same async RAG/DB code without rewriting it sync.

Concrete examples from the fca project context

Example 1

ingest_pdf_task is a sync Celery function; inside it await service.ingest_pdf(file_path) once the loop is bridged.

Example 2

send_email_task reuses the same bridge for any future async-only task.

Example 3

Keep the bridge tiny and named (run_until_complete) so it’s a one-line audit.

Data flow / flow chart

Celery broker -> worker -> run_until_complete -> RAGService.ingest_pdf()

Takeaway

Sync Celery and async business logic don’t fight — bridge the loop in one place and you’re done.