由于其异步能力、自动创建的文档和高性能,FastAPI赢得了巨大的人气。在这篇博客文章中,我们将介绍如何构建一个基于 FastAPI 的 Python 应用程序,该应用程序可以处理在线和离线请求(例如同步API请求和使用Amazon SQS队列的后台任务)。我们将介绍生产就绪的最佳实践、处理线程管理和实现定时任务。
1.: 应用设计概览一个可投入生产的健壮 FastAPI 应用架构通常包含:
- API 层: 负责处理同步的 API 请求。
- 后台工作者层: 处理长时间运行或异步的任务,使用队列(如 SQS)。
- 数据库和缓存层: 存储响应所需的数据。
- 任务调度器: 用于安排定期任务。
- 监控与健康检查: 用于确保系统的可观察性。
这里有一个高层次的设计图,便于大家理解:
2. 设置 FastAPI 应用程序:API Gateway → FastAPI 应用程序 → (同步响应消息)
→ SQS 消息队列 → 后台任务处理程序 → 数据库和缓存
我们先来构建一个 FastAPI 项目结构:
这是一个简单的应用目录结构示例。
app/
├── main.py
├── API/
│ └── 接口.py
├── 任务执行器/
│ └── 背景任务.py
├── 数据模型/
│ └── 模型.py
├── 配置.py
└── 工具/
└── 调度器.py
main.py (主程序)
from fastapi import FastAPI, BackgroundTasks
from app.api.endpoints import router as api_router
import boto3
import os
app = FastAPI()
# 初始化SQS客户端实例
sqs_client = boto3.client(
"sqs",
region_name=os.getenv("AWS_REGION"),
aws_access_key_id=os.getenv("AWS_ACCESS_KEY_ID"),
aws_secret_access_key=os.getenv("AWS_SECRET_ACCESS_KEY")
)
@app.get("/health")
def health_check():
return {"status": "ok"}
# 加入API端点定义
app.include_router(api_router)
3. 处理在线请求(同步API)
这里有一个直接处理用户请求的 API 端点的例子。
# endpoints.py
from fastapi import APIRouter, HTTPException
from app.workers.background_tasks import enqueue_task
router = APIRouter()
@router.post("/process-online")
def process_online(data: dict):
# 执行在线同步处理
result = {"message": "在线处理成功完成", "input": data}
return result
@router.post("/process-offline")
def process_offline(data: dict):
# 将任务加入队列等待离线处理
enqueue_task(data)
return {"message": "任务已加入队列等待离线处理"}
4. 使用SQS处理非实时请求(后台任务)
一个后台工作者监听着SQS队列中的消息并进行处理。
workers/背景任务.py
import boto3
import time
import os
sqs_queue_url = os.getenv("SQS_QUEUE_URL")
# 向SQS队列中入队任务
def enqueue_task(data):
sqs_client.send_message(
QueueUrl=sqs_queue_url,
MessageBody=str(data)
)
print("打印 '消息已发送到SQS'")
# 轮询SQS队列的工作函数
def process_sqs_messages():
while True:
messages = sqs_client.receive_message(
QueueUrl=sqs_queue_url,
MaxNumberOfMessages=10,
WaitTimeSeconds=10
)
if 'Messages' in messages:
for message in messages['Messages']:
print("打印 '正在处理消息:', message['Body']")
# 在这里执行耗时处理
time.sleep(2) # 模拟处理时间
# 处理完成后删除消息
sqs_client.delete_message(
QueueUrl=sqs_queue_url,
ReceiptHandle=message['ReceiptHandle']
)
运行后台任务:
在命令行中输入以下命令来运行处理SQS消息的脚本:
python -m app.workers.background_tasks.process_sqs_messages
注释: 这是一个用于处理SQS消息的Python命令。python -m
语法用于运行Python的模块或包。
默认,FastAPI 使用异步协程处理并发情况。不过,特定任务可能需要线程。
例子:并行执行任务:如果你想实现并行处理,可以试试使用 concurrent.futures.ThreadPoolExecutor
这个工具。它可以帮助你在程序中实现并行执行,从而提高效率。
import concurrent.futures
from fastapi import BackgroundTasks
executor = concurrent.futures.ThreadPoolExecutor(max_workers=5)
@app.get("/heavy-task")
def run_heavy_task():
future = executor.submit(expensive_function)
return {"message": "任务正在执行"}
6. FastAPI中的生命周期
FastAPI 提供了一个生命周期处理器函数,在应用启动和关闭时执行代码。
from fastapi import FastAPI
from contextlib import asynccontextmanager
@asynccontextmanager
async def lifespan(app: FastAPI):
print("开始启动...")
yield
print("开始关闭...")
app = FastAPI(lifespan=lifespan)
用寿命来,
或者更口语化地表达为:用寿命来干啥:
- 初始化数据库连接过程,
- 启动后台任务。
虽然 FastAPI 本身没有内置的功能支持定时任务,你可以使用例如 APScheduler
或 Celery
这样的第三方库来执行周期性任务。
from apscheduler.schedulers.background import BackgroundScheduler
scheduler = BackgroundScheduler()
# 定义周期性任务
@scheduler.scheduled_job("间隔", seconds=60)
def 周期性任务():
print("执行计划任务")
scheduler.start()
@app.on_event("关闭")
def 关闭事件():
scheduler.shutdown()
示例
- 在线API请求: 用户提交的数据会被立即处理并返回。
- 离线处理: 大型文件或耗时较长的请求会被加入SQS队列并在稍后处理。
- 定时任务: 每分钟,都会将处理的任务报告发送到监控系统。
- 环境变量: 使用
.env
文件和 AWS Secrets Manager 来管理敏感配置信息。 - 安全: 使用 OAuth2 或 JWT 进行 API 认证。
- 可扩展性: 在负载均衡器(如 AWS ALB)后面部署 FastAPI。
- 监控: 与 Prometheus/Grafana 集成以监控性能指标。
- 重试和死信队列: 配置 SQS 以处理重试逻辑,并将未处理的任务移至死信队列(DLQ)。
FastAPI 的轻量级和异步功能使其成为构建既处理在线请求又处理离线请求的 API 的绝佳选择。通过利用 SQS 等工具进行后台任务处理以及 APScheduler 进行定时任务,您可以创建一个健壮且可投入生产的系统。通过周全的设计、适当的线程管理和有效的监控,您的 FastAPI 应用程序将在实际应用中具备高扩展性和高效率。