celery模块介绍
一、介绍
Celery 是一款基于 Python 的分布式任务队列框架,核心解决「异步任务执行」「定时任务调度」「任务结果存储」问题, 广泛用于 Django/Flask 项目的异步处理(如邮件发送、数据导出、定时归档)、定时任务(如定时清理日志、定时同步数据)等场景。二、核心组件介绍
| 组件 | 作用 | 通俗解释 |
|---|---|---|
| Celery 实例 | 任务队列的核心入口,配置 / 注册任务 | 任务队列的 “总控中心” |
| 任务(Task) | 异步 / 定时执行的函数,用 @app.task 或者@shared_task装饰 | 要异步或定时做的 “活儿”(如发送邮件、生成报表) |
| 工作节点(Worker) | 执行任务的进程 / 服务器,可分布式部署 | 干活的 “工人”,可多台机器同时干活 |
| 消息中间件(Broker) | 存储待执行的任务队列,Celery 仅生产 / 消费任务 | 任务的 “中转站”(如 Redis/RabbitMQ) |
| 结果后端(Result Backend) | 存储任务执行结果(成功 / 失败 / 返回值) | 任务结果的 “仓库”(如 Redis/MySQL/PostgreSQL) |
| 定时任务(Beat) | 周期性触发定时任务的调度器 | 定时任务的 “闹钟”,到点把任务丢给 Broker |
| 任务装饰器 | @app.task 基础装饰器,@shared_task 跨应用装饰器 | 标记函数为 “可异步执行的任务” |
三、环境搭建
1、安装核心包
# 基础安装(含 Celery 核心)
pip install celery
# 可选依赖(根据 Broker/Result Backend 选择)
pip install redis # 用 Redis 做 Broker/Result Backend
pip install django-celery-beat # Django 集成celery 定时任务
2、选择 Broker(消息中间件)
可以使用redis、rabbitmq、数据库等,
生产环境优先选 Redis(与 Django 生态适配最佳),下文均以 Redis 为例
四、基础用法(纯 Python 示例)
1. 第一步:编写 Celery 配置与任务新建项目目录结构:
celery_demo/
├── celery_app.py # Celery 实例配置
└── tasks.py # 任务函数必须放在这个文件中,文件名不能叫别的
(1)配置 Celery 实例(celery_app.py里配置)
from celery import Celery
# 1. 初始化 Celery 实例
app = Celery(
'celery_demo', # 项目名(任意)
broker='redis://localhost:6379/0', # Broker 地址(Redis 第0库)
backend='redis://localhost:6379/1', # 结果后端(Redis 第1库)
include=['tasks'] # 自动发现的任务文件(就是tasks.py)
)
# 2. 基础配置(可选,也可写在单独的 config.py 中)
app.conf.update(
task_serializer='json', # 任务序列化格式
result_serializer='json', # 结果序列化格式
accept_content=['json'], # 接受的内容类型
timezone='Asia/Shanghai', # 时区(必须设置,否则定时任务时区错乱)
enable_utc=False, # 关闭 UTC 时区
task_acks_late=True, # 任务执行完再确认(避免 worker 崩溃丢失任务)
worker_prefetch_multiplier=1, # 每个 worker 每次取 1 个任务(避免任务堆积)
)
(2)定义任务(tasks.py)
from celery_app import app
import time
# 基础异步任务:用 @app.task 装饰
@app.task
def async_send_email(to_email, content):
"""异步发送邮件(模拟耗时操作)"""
time.sleep(3) # 模拟网络延迟
print(f"邮件发送成功:{to_email},内容:{content}")
return f"Success: {to_email}"
# 带重试的任务:处理临时失败(如网络波动)
@app.task(bind=True, max_retries=3, retry_backoff=2)
def async_export_data(self, file_name):
"""异步导出数据,失败自动重试"""
try:
time.sleep(5)
# 模拟异常(如数据库连接失败)
if file_name == "error_file":
raise Exception("数据库连接超时")
print(f"数据导出成功:{file_name}")
return f"Exported: {file_name}"
except Exception as e:
# 触发重试,间隔 2^retry_count 秒(retry_backoff=2)
self.retry(exc=e, countdown=2 ** self.request.retries)
# 定时任务:后续结合 Beat 调度
@app.task
def async_clean_logs():
"""定时清理日志(模拟)"""
print("定时任务:清理7天前的日志文件")
return "Logs cleaned"
2. 第二步:启动 Worker
打开终端,进入 celery_demo 目录,启动 Worker:
# 基础启动
celery -A celery_app worker --loglevel=info
# 进阶启动(指定并发数、节点名)
celery -A celery_app worker -c 4 --hostname=worker1@%h --loglevel=info
# -c 4:4个并发进程(建议等于 CPU 核心数)
# --hostname:节点名,分布式部署时分不同 worker,单机部署不用管这个
启动成功会看到如下日志(关键信息):
plaintext
-------------- celery@worker1@xxx v5.3.4 (emerald-rush)
--- ***** -----
-- ******* ---- Linux-5.15.0-88-generic-x86_64-with-glibc2.35 2025-12-19 10:00:00
- *** --- * ---
- ** ---------- [config]
- ** ---------- .> app: celery_demo:0x7f8b1c0b2d00
- ** ---------- .> broker: redis://localhost:6379/0
- ** ---------- .> backend: redis://localhost:6379/1
- ** ---------- .> concurrency: 4 (prefork)
- *** --- * --- .> task events: OFF (enable -E to monitor tasks in real time)
-- ******* ----
--- ***** ----- [queues]
-------------- .> celery exchange=celery(direct) key=celery
[tasks]
. tasks.async_clean_logs
. tasks.async_export_data
. tasks.async_send_email
[2025-12-19 10:00:00,000: INFO/MainProcess] celery@worker1@xxx ready.
3. 第三步:触发异步任务
打开另一个新终端,进入 Python 交互环境,手动触发任务:
from tasks import async_send_email, async_export_data
# 1. 触发异步任务(非阻塞,立即返回任务 ID)
# 格式:任务名.delay(参数1,参数2 ...),参数就是你任务函数的参数
# delay就是异步执行的方法
task1 = async_send_email.delay("user@example.com", "Celery 异步邮件测试")
print("任务ID:", task1.id) # 输出:任务ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
# 2. 查看任务状态/结果
print("任务状态:", task1.state) # PENDING -> SUCCESS
print("任务结果:", task1.get(timeout=10)) # 获取结果(timeout 防止卡死)
# 3. 触发带重试的任务(模拟失败)
task2 = async_export_data.delay("error_file")
# 查看重试过程:第一次失败 → 2秒后重试 → 最多3次
4. 第四步:配置定时任务(Beat 调度)
(1)修改 celery_app.py,添加定时任务配置
from celery import Celery
from celery.schedules import crontab # 定时任务表达式
app = Celery(
'celery_demo',
broker='redis://localhost:6379/0',
backend='redis://localhost:6379/1',
include=['tasks']
)
# 基础配置(不变)
app.conf.update(
timezone='Asia/Shanghai',
enable_utc=False,
# 定时任务调度规则
beat_schedule={
'clean-logs-daily': { # 任务名(任意)
'task': 'tasks.async_clean_logs', # 要执行的任务函数
'schedule': crontab(hour=0, minute=0), # 每天凌晨0点执行
# 'schedule': 30.0, # 简单间隔(每30秒执行,适合测试)
'args': (), # 任务无参数则空元组
},
'export-data-hourly': {
'task': 'tasks.async_export_data',
'schedule': crontab(minute=0), # 每小时整点执行
'args': ("hourly_report.csv",),
},
},
)
(2)启动 Beat 调度器(定时触发任务)
打开一个新终端,启动 Beat:
celery -A celery_app beat --loglevel=info
启动成功会看到:
celery beat v5.3.4 (emerald-rush) is starting.
__ - ... __ - _
LocalTime -> 2025-12-19 10:00:00
Configuration ->
. broker -> redis://localhost:6379/0
. loader -> celery.loaders.app.AppLoader
. scheduler -> celery.beat.PersistentScheduler
. db -> celerybeat-schedule
. logfile -> [stderr]@%INFO
. maxinterval -> 5.00 seconds (5s)
[2025-12-19 10:00:00,000: INFO/MainProcess] beat: Starting...
[2025-12-19 10:00:00,000: INFO/MainProcess] Scheduler: Sending due task clean-logs-daily (tasks.async
Beat 会按配置的规则,定时将任务发送到 Broker,Worker 会从broker中获取任务自动执行。
五、Django 集成 Celery
Django 项目集成 Celery 是最常见的场景,以下是标准化配置流程(基于 Django 4.2+)。
1. Django 项目目录结构
django_celery_demo/
├── django_celery_demo/ # 项目根配置
│ ├── __init__.py
│ ├── settings.py # Django 配置文件
│ ├── urls.py
│ └── celery.py # Celery 核心配置(关键)
├── apps/ # 业务app
│ ├── __init__.py
│ ├── tasks.py # 任务必须放在这个文件中
│ ├── models.py
│ └── views.py # 视图中触发任务
├── manage.py
└── requirements.txt
2. 配置 Celery 核心文件(django_celery_demo/celery.py)
import os
from celery import Celery
from celery.schedules import crontab
# 1. 设置 Django 环境变量(必须)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_celery_demo.settings')
# 2. 初始化 Celery 实例
app = Celery('django_celery_demo')
# 3. 从 Django settings 中读取 Celery 配置(命名空间:CELERY_)
app.config_from_object('django.conf:settings', namespace='CELERY')
# 4. 自动发现所有 Django 应用中的 tasks.py 文件
app.autodiscover_tasks()
# 5. 配置 django-celery-beat(动态定时任务核心),如果不用定时任务可以不配置
# 这个配置好后,执行迁移命令,会在数据库中生成几张表,然后需要在表里面配置
定时任务和对应的任务函数名称,这个自行研究
app.conf.update(
# 使用数据库调度器(动态 crontab 依赖),会在数据库中创建几张表
beat_scheduler='django_celery_beat.schedulers.DatabaseScheduler',
# 时区(避坑:必须和 Django 时区一致,否则定时任务时间偏移)
timezone='Asia/Shanghai',
# 关闭静态定时配置(只用数据库动态规则)
beat_schedule={},
# 任务结果过期时间(避免 Redis 数据堆积),用celery存储运行结果是可选的,我这里没用celery来存储结果
# result_expires=3600,
# 防止数据库连接泄漏(避坑:关键配置)
worker_pool_restarts=True,
)
# 6. 可选:任务执行前的钩子(如打印日志)
@shared_task(bind=True, ignore_result=True)
def debug_task(self):
print(f'Request: {self.request!r}')
import os
from celery import Celery
from celery.schedules import crontab
# 1. 设置 Django 环境变量(必须)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_celery_demo.settings')
# 2. 初始化 Celery 实例
app = Celery('django_celery_demo')
# 3. 从 Django settings 中读取 Celery 配置(命名空间:CELERY_)
app.config_from_object('django.conf:settings', namespace='CELERY')
# 4. 自动发现所有 Django 应用中的 tasks.py 文件
app.autodiscover_tasks()
# 5. 配置 django-celery-beat(动态定时任务核心),如果不用定时任务可以不配置
# 这个配置好后,执行迁移命令,会在数据库中生成几张表,然后需要在表里面配置
定时任务和对应的任务函数名称,这个自行研究
app.conf.update(
# 使用数据库调度器(动态 crontab 依赖),会在数据库中创建几张表
beat_scheduler='django_celery_beat.schedulers.DatabaseScheduler',
# 时区(避坑:必须和 Django 时区一致,否则定时任务时间偏移)
timezone='Asia/Shanghai',
# 关闭静态定时配置(只用数据库动态规则)
beat_schedule={},
# 任务结果过期时间(避免 Redis 数据堆积),用celery存储运行结果是可选的,我这里没用celery来存储结果
# result_expires=3600,
# 防止数据库连接泄漏(避坑:关键配置)
worker_pool_restarts=True,
)
# 6. 可选:任务执行前的钩子(如打印日志)
@shared_task(bind=True, ignore_result=True)
def debug_task(self):
print(f'Request: {self.request!r}')
3. 修改 Django 项目 init.py(django_celery_demo/init.py)
# 确保 Django 启动时加载 Celery 实例:
from .celery import app as celery_app
__all__ = ('celery_app',)
4. 配置 Django settings.py(关键)
# ========== Celery 核心配置 ==========
# 1. Broker 地址(Redis)
CELERY_BROKER_URL = 'redis://localhost:6379/0'
# 2. 结果后端地址
CELERY_RESULT_BACKEND = 'redis://localhost:6379/1'
# 3. 时区(必须和 Django 时区一致)
CELERY_TIMEZONE = 'Asia/Shanghai'
CELERY_ENABLE_UTC = False
# 4. 任务序列化/反序列化
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_ACCEPT_CONTENT = ['json']
# 5. 任务结果过期时间(默认1天,按需调整)
CELERY_RESULT_EXPIRES = 86400
# 6. Worker 配置
CELERY_WORKER_PREFETCH_MULTIPLIER = 1 # 每次取1个任务,避免堆积
CELERY_WORKER_MAX_TASKS_PER_CHILD = 1000 # 每个 worker 执行1000个任务后重启,防止内存泄漏
# 7. 可选:用 Django 数据库存储任务结果(需安装 django-celery-results),也可以存在redis中
# INSTALLED_APPS 中添加 'django_celery_results'
# CELERY_RESULT_BACKEND = 'django-db'
# CELERY_CACHE_BACKEND = 'django-cache'
# ========== Django 基础配置 ==========
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'apps', # 注册app
# celery
'django_celery_beat', # 定时任务
# 'django_celery_results', # 可选:存储任务结果到数据库,也可以直接存到redis
]
TIME_ZONE = 'Asia/Shanghai'
USE_TZ = True
5. 定义业务任务(apps/tasks.py)
使用 @shared_task 替代 @app.task,避免跨应用依赖:from celery import shared_task
from django.db import transaction
from apps.task_app.models import Archive, PeriodicTask
import time
# 归档任务(业务示例)
@shared_task(bind=True, max_retries=3, retry_backoff=3)
def async_archive_data(self):
try:
with transaction.atomic():
# 模拟耗时操作:查询7天前的任务数据
old_tasks = PeriodicTask.objects.filter(create_time__lt=time.time() - 604800)
# 批量创建归档记录
archive_list = [Archive(task_id=t.id, name=t.name, crontab=t.crontab) for t in old_tasks]
Archive.objects.bulk_create(archive_list)
# 标记原任务为已归档
old_tasks.update(is_archived=True)
return f"归档成功:{len(old_tasks)} 条记录"
except Exception as e:
# 任务失败重试
self.retry(exc=e, countdown=3 ** self.request.retries)
6. 视图中触发异步任务(apps/task_app/views.py)
from django.shortcuts import render
from django.http import JsonResponse
from .tasks import async_handle_form_submit
def asyncarchive_data(request):
if request.method == 'POST':
form_data = {
'name': request.POST.get('name'),
'crontab': request.POST.get('crontab'),
}
# 触发异步任务(非阻塞,立即返回)
task = async_archive_data.delay()
# 返回任务ID,前端可轮询查询状态
return JsonResponse({
'code': 200,
'msg': '任务已提交',
'task_id': task.id
})
return render(request, 'submit_form.html')
7. 启动 Django + Celery 服务
1)启动 Django 服务
python manage.py runserver 0.0.0.0:8000
2)启动 Celery Worker
celery -A django_celery_demo worker --loglevel=info
3)启动 Celery Beat(定时任务),如果有定时任务这个必须启动
celery -A django_celery_demo beat --loglevel=info --logfile=celery_beat.log
# 定时任务触发流程
1. 配置 beat_schedule → 定义“每天2点执行 async_archive_data 任务”
2. 启动 Beat 进程 → Beat 按规则“到点检查”(比如每天2点)
3. Beat 触发任务 → 把 async_archive_data 任务发送到 Redis Broker
4. 启动 Worker 进程 → Worker 从 Broker 取出任务并执行
六、Celery 高级特性(生产必备)
1. 任务优先级与队列
不同任务分配到不同队列,优先执行高优先级任务(如支付 > 日志清理)# 1. 配置队列
app.conf.task_queues = {
'high_priority': {'exchange': 'high_priority', 'routing_key': 'high'},
'low_priority': {'exchange': 'low_priority', 'routing_key': 'low'},
}
# 2. 任务绑定队列
@shared_task(queue='high_priority')
def async_pay_order(order_id):
"""高优先级:支付任务"""
pass
@shared_task(queue='low_priority')
def async_clean_cache():
"""低优先级:清理缓存"""
pass
# 3. Worker 只消费指定队列
celery -A django_celery_demo worker -Q high_priority --loglevel=info # 只处理高优先级任务
2. 任务限流与超时
防止任务占用过多资源:# 1. 单个任务超时(超过10秒终止)
@shared_task(time_limit=10, soft_time_limit=8)
def async_long_task():
"""soft_time_limit:软超时(触发信号),time_limit:硬超时(强制终止)"""
time.sleep(15)
# 2. 全局限流(Worker 每秒最多执行5个任务)
app.conf.task_annotations = {
'apps.task_app.tasks.async_export_data': {'rate_limit': '5/s'},
}
3. 任务钩子与信号
监听任务生命周期(如失败报警、成功记录):from celery.signals import task_success, task_failure
# 任务成功钩子
@task_success.connect(sender=async_archive_data)
def task_success_handler(sender=None, result=None, **kwargs):
print(f"任务 {sender.request.id} 成功,结果:{result}")
# 可选:发送钉钉/企业微信通知
# 任务失败钩子
@task_failure.connect(sender=async_archive_data)
def task_failure_handler(sender=None, exception=None, **kwargs):
print(f"任务 {sender.request.id} 失败,异常:{exception}")
# 可选:发送报警邮件
4. 分布式 Worker 部署
多台服务器部署 Worker,共享同一个 Redis Broker,实现任务分布式执行:# 服务器1
celery -A django_celery_demo worker --hostname=worker1@server1 --loglevel=info
# 服务器2
celery -A django_celery_demo worker --hostname=worker2@server2 --loglevel=info
5.监控 Celery 任务
flower:Celery 官方监控工具,可视化任务状态 / Worker 状态点击查看代码
pip install flower
celery -A django_celery_demo flower --port=5555 # 访问 http://localhost:5555

浙公网安备 33010602011771号