Короткий ответ
Эндпоинт запуска операции должен немедленно отвечать 202 Accepted с идентификатором задачи и ссылкой на статус, а не ждать завершения в рамках HTTP-запроса; клиент далее опрашивает отдельный эндпоинт статуса (или получает webhook по завершении).
Как это работает подробнее
202 означает "запрос принят к обработке, но результат пока не готов" — в отличие от синхронных операций, где финальный статус известен сразу. Обработка переносится в фоновую задачу (воркер, очередь задач, например Celery/RQ/встроенный BackgroundTasks), а API-слой лишь регистрирует задачу и возвращает идентификатор.
Пример кода
example.py
from fastapi import FastAPI, BackgroundTasks
import uuid
app = FastAPI()
tasks = {}
def generate_report(task_id: str, params: dict):
tasks[task_id]["status"] = "running"
try:
result = build_report(params) # потенциально долгая операция
tasks[task_id] = {"status": "done", "result_url": result}
except Exception as exc:
tasks[task_id] = {"status": "failed", "error": str(exc)}
@app.post("/reports", status_code=202)
def start_report(params: dict, background_tasks: BackgroundTasks):
task_id = str(uuid.uuid4())
tasks[task_id] = {"status": "pending"}
background_tasks.add_task(generate_report, task_id, params)
return {"task_id": task_id, "status_url": f"/reports/{task_id}"}
@app.get("/reports/{task_id}")
def get_report_status(task_id: str):
return tasks.get(task_id, {"status": "not_found"})Что использовать на практике
- Рекомендация. эндпоинт статуса должен возвращать состояние (
pending/running/done/failed) и, при завершении, либо сам результат, либо ссылку на него (например, URL для скачивания отчёта); если ожидаемое время выполнения велико и известно заранее, можно дополнительно поддержать webhook-уведомление вместо постоянного polling клиентом. Выбор между частым коротким polling и webhook зависит от того, насколько клиент терпим к задержке узнавания результата и насколько он способен принимать входящие запросы.
Подводные камни
- Риски. держать HTTP-соединение открытым на время всей долгой операции (синхронный эндпоинт с длинным таймаутом), что хрупко при сбоях сети и не масштабируется при множестве одновременных долгих операций; не предусматривать способ узнать, что задача зависла или провалилась — клиент должен получать явный статус
failedс причиной, а не вечно видетьpending.