1. 背景与核心概念
1.1 为什么需要任务告警与自修复
在分布式系统中,后台任务失败不可避免。FastAPI + Celery 组合提供了强大的异步任务处理能力,但当任务失败时:
- 关键业务流程可能中断
- 用户体验可能受影响
- 系统资源可能被占用无法释放
1.2 核心组件
graph TD
A[任务失败] --> B(Celery事件捕获)
B --> C{失败类型分析}
C --> D[网络超时类]
C --> E[资源不足类]
C --> F[逻辑错误类]
D --> G[自动重试机制]
E --> H[资源扩容方案]
F --> I[人工介入告警]
2. 实现方案
2.1 任务监控架构设计
# requirements.txt
fastapi==0.95.0
celery==5.2.7
pydantic==1.10.7
redis==4.5.5
flower==1.2.0 # Celery监控面板
2.2 自动重试与告警实现
from celery import Celery, Task
from pydantic import BaseModel
import smtplib
app = Celery('tasks', broker='redis://localhost:6379/0')
class TaskConfig(BaseModel):
max_retries: int = 3
retry_backoff: int = 10 # 秒
alert_emails: list[str] = []
@app.task(bind=True)
def critical_task(self, data: dict):
"""关键业务任务示例"""
try:
# 业务逻辑实现
result = process_data(data)
return result
except NetworkException as e:
# 可自动恢复的异常
self.retry(exc=e, countdown=self.request.retry_backoff)
except BusinessLogicException as e:
# 需要人工干预的异常
send_alert(f"业务逻辑错误: {str(e)}", self.request.alert_emails)
def send_alert(message: str, emails: list[str]):
"""发送告警邮件"""
smtp_server = smtplib.SMTP('smtp.example.com', 587)
smtp_server.starttls()
smtp_server.login('alert@example.com', 'password')
for email in emails:
smtp_server.sendmail(
'alert@example.com',
email,
f"Subject: 任务告警\n\n{message}"
)
3. 故障诊断与修复流程
3.1 自动修复策略矩阵
| 故障类型 | 自动修复方案 | 人工介入条件 |
|---|---|---|
| 网络超时 | 指数退避重试(最高3次) | 连续失败>3次 |
| 数据库连接失败 | 连接池重连+缓存补偿 | 持续时间>10分钟 |
| 第三方API失效 | 备用接口切换 | 所有备用接口均失效 |
| 资源不足(OOM) | 自动扩容Worker | 单任务内存>1GB |
3.2 生产环境最佳实践
- 任务分级管理
# 任务配置模型
class CriticalTaskConfig(TaskConfig):
max_retries: int = 5
retry_backoff: int = 30
alert_emails: list[str] = ['admin@company.com']
class BackgroundTaskConfig(TaskConfig):
max_retries: int = 1
alert_emails: list[str] = []
- 死亡任务处理
@app.task(bind=True, max_retries=3, reject_on_worker_lost=True)
def resilient_task(self):
# 开启拒绝任务丢失功能
# 当worker崩溃时任务不会丢失
...
4. 课后 Quiz
Q1: 如何防止自动重试导致的雪崩效应?
A:
- 使用指数退避算法(如 Celery 的
retry_backoff) - 设置最大重试次数限制
- 对依赖服务实现断路器模式
Q2: 为什么使用 Pydantic 模型进行任务配置?
A:
- 获得类型安全验证
- 自动生成文档
- 避免非法配置导致的任务故障
5. 常见报错解决方案
报错1:WorkerLostError ("Worker exited prematurely")
原因:
- Worker 进程意外崩溃
- 内存泄漏导致 OOM 被杀
解决方案:
- 检查内存监控数据
- 限制单任务内存使用:
from resource import setrlimit, RLIMIT_AS setrlimit(RLIMIT_AS, (1_000_000_000, 1_000_000_000)) # 限制1GB - 添加任务心跳检测
报错2:SoftTimeLimitExceeded
原因:
- 任务执行超时
解决方案:
- 优化任务逻辑
- 合理设置时间限制:
@app.task(soft_time_limit=300, time_limit=330) def long_running_task(): # soft_time_limit:优雅停止时间 # time_limit:强制终止时间
报错3:IncompleteResult("No result yet")
原因:
- 任务结果后端连接失败
- 结果过期被删除
解决方案:
- 检查 Redis/Memcached 连接状态
- 增加结果超时设置:
app.conf.result_expires = 3600 * 24 # 结果保留24小时 - 实现结果缓存持久化