FastAPI与Celery的完美邂逅,如何让异步任务飞起来?

242 阅读2分钟

FastAPI框架集成Celery实战

1. 环境准备与安装

需要Python 3.8+环境,推荐使用虚拟环境管理依赖。核心依赖包及版本:

fastapi==0.95.2
celery==5.3.0
redis==4.5.5
pydantic==1.10.7
uvicorn==0.22.0

安装命令:

pip install fastapi celery[redis] pydantic uvicorn

2. 配置Celery实例

在项目根目录创建celery_app.py

from celery import Celery
from pydantic import BaseModel

class TaskResult(BaseModel):
    task_id: str
    status: str
    result: dict = None

celery_app = Celery(
    'fastapi_worker',
    broker='redis://localhost:6379/0',
    backend='redis://localhost:6379/1',
    include=['task_handlers']
)

celery_app.conf.update(
    task_serializer='json',
    accept_content=['json'],
    result_serializer='json',
    timezone='Asia/Shanghai'
)

3. 异步任务处理流程

graph TD
    A[用户请求] --> B[FastAPI路由]
    B --> C[控制器调用Celery任务派发]
    C --> D[Celery Broker接收任务]
    D --> E[Worker进程获取任务]
    E --> F[执行任务]
    F --> G[结果存入Backend]
    G --> H[客户端通过ID查询结果]
  1. 用户请求通过FastAPI路由进入
  2. 控制器调用Celery任务派发接口
  3. Celery Broker(Redis)接收任务
  4. Worker进程从Broker获取任务
  5. 任务执行结果存入Backend
  6. 客户端通过任务ID查询结果

4. 接口层实现

创建main.py

from fastapi import FastAPI, HTTPException
from celery.result import AsyncResult
from pydantic import BaseModel
from celery_app import celery_app, TaskResult

app = FastAPI()

class EmailRequest(BaseModel):
    recipient: str
    content: str

@app.post("/send-email")
async def send_email(request: EmailRequest):
    task = celery_app.send_task('send_email_task', args=[request.dict()])
    return {"task_id": task.id}

@app.get("/task-status/{task_id}")
def get_task_status(task_id: str):
    task_result = AsyncResult(task_id, app=celery_app)
    return TaskResult(
        task_id=task_id,
        status=task_result.status,
        result=task_result.result if task_result.ready() else None
    )

5. 任务处理器实现

创建task_handlers.py

from celery import shared_task
from pydantic import ValidationError
from datetime import datetime

@shared_task(name='send_email_task')
def send_email_task(params):
    try:
        # 模拟邮件发送耗时操作
        print(f"[{datetime.now()}] Sending email to {params['recipient']}")
        return {"status": "success", "message": "Email queued"}
    except ValidationError as e:
        return {"status": "error", "detail": str(e)}

6. 任务监控配置

在Celery配置中添加:

celery_app.conf.update(
    worker_send_task_events=True,
    task_send_sent_event=True,
    event_queue_ttl=60,
)

启动监控命令:

celery -A celery_app flower --port=5555

课后Quiz

发现1000+提升效率与开发的AI工具和实用程序tools.cmdragon.cn/

Q1:如何防止重复提交相同任务? A:通过请求参数生成唯一任务ID,使用Celery的task_reject_on_worker_lost配置

Q2:异步任务结果如何持久化? A:配置Redis作为Backend存储,使用AsyncResult查询结果

Q3:如何监控任务执行状态? A:通过Flower监控平台查看任务统计信息

常见报错处理

  1. Worker启动失败:
[ERROR] Cannot connect to redis://localhost:6379/0

解决方法:检查Redis服务状态,确认防火墙设置

  1. 任务执行超时:
{"error": "TaskTimeoutError"}

解决方法:调整task_time_limit配置参数

  1. 结果反序列化失败:
{"error": "ResultDecodeError"}

解决方法:确保任务返回JSON可序列化对象