Celery基础(异步任务、延迟任务、定时任务)
介绍
Celery是基于Python编写的分布式异步任务框架,Celery只是用来调度任务的,其本身不具备存储任务的功能,因此需要借助像Redis、消息队列、数据库之类的存储工具,官方推荐的消息队列是RabbitMQ,而我们使用Redis
使用场景
- 异步任务
- 视频转码、邮件发送、消息推送等
- 定时任务
- 定时发送消息之类
- 延迟任务
- 提交任务后,在一段时间后再执行某个任务
Celery架构
Celery使用的是典型的生产者消费者模式,其主要由以下部分组成:
- Celery Beat:任务调度器,Beat进程会读取配置文件的内容,并周期性的将配置中到期需要执行的任务发送给消息队列
- Producer:需要在队列中进行的任务,一般由用户、触发器或其他操作将任务拉入队,然后交由workers进行处理。调用了 Celery 提供的 API、函数或者装饰器而产生任务并交给任务队列处理的都是任务生产者
- Broker:消息中间件,在这里指的是任务队列本身,Celery扮演生产者和消费者角色,brokers就是生产者和消费者存放/拿取产品的地方(队列)
- Celery Worker:执行任务的消费者,从队列中取出任务并执行。通常会在多台服务器运行多个消费者来提高执行效率
- Result Backend:任务处理完后保存状态信息和结果,以供查询,Celery 默认已支持 Redis、RabbitMQ、MongoDB、Django ORM、SQLAlchemy 等方式
启动指令
终端使用命令时必须将路径定位到app文件所在的包中
# 启动worker
celery -A tasks worker -l info -P eventlet
# 启动beat
celery -A tasks beat -l info
快速使用
Python版本支持:
- Celery version 5.3.5 runs on:
- Python (3.8, 3.9, 3.10, 3.11, 3.12)
- PyPy3.9+ (v7.3.12+)
- Python 3.7: Celery 5.2 or earlier.
- Python 3.6: Celery 5.1 or earlier.
- Python 2.7: Celery 4.x series.
- Python 2.6: Celery series 3.1 or earlier.
- Python 2.5: Celery series 3.0 or earlier.
- Python 2.4: Celery series 2.2 or earlier.
安装:
pip install celery
pip install redis
# win平台运行,如果是mac,linux不需要
pip install eventlet
创建tasks主文件
# tasks.py
from celery import Celery
from redis import Redis
broker = 'redis://127.0.0.1:6379/1'
backend = 'redis://127.0.0.1:6379/2'
app = Celery('tasks',broker=broker,backend=backend)
@app.task
def add(x,y):
return x+y
add_task.py 提交任务
# add_task.py
from tasks import add
from tasks import app
# 同步调用(直接打印结果)
res=send_email()
print(res)
# 异步调用
res = add.delay(10, 20)
print(res.id)
启动worker
celery -A tasks worker -l info -P eventlet
tasks
:注册app的py文件名-P
:Windows系统
获取任务id
c48af49b-5169-4d5b-b2ab-13ad5f4d264c
结果存储并查看
# get_res.py
from celery.result import AsyncResult
from tasks import app
id = 'c48af49b-5169-4d5b-b2ab-13ad5f4d264c'
result = AsyncResult(id=res.id, app=app)
if result.successful():
result = result.get()
print(result)
elif result.failed():
print('任务失败')
elif result.status == 'PENDING':
print('任务等待中被执行')
elif result.status == 'RETRY':
print('任务异常后正在重试')
elif result.status == 'STARTED':
print('任务已经开始被执行')
# 结果:30
目录结构
项目名
├── celery_task # celery包
│ ├── __init__.py # 包文件
│ ├── tasks.py # app主文件
│ └── user_tasks.py # 所有任务函数
└── order_tasks.py # 所有任务函数
├── add_task.py # 添加任务
└── get_res.py # 获取结果
异步任务
也就是.delay
方法
# tasks.py
# 创建app和需要执行的函数add
from celery import Celery
from redis import Redis
broker = 'redis://127.0.0.1:6379/1'
backend = 'redis://127.0.0.1:6379/2'
app = Celery('tasks',broker=broker,backend=backend)
@app.task
def add(x,y):
return x+y
# get_res.py
# 模拟异步任务的提交和获取
from tasks import add
from celery.result import AsyncResult
from tasks import app
def get_task(id):
result = AsyncResult(id=id, app=app)
if result.successful():
result = result.get()
print(result)
elif result.failed():
print('任务失败')
elif result.status == 'PENDING':
print('任务等待中被执行')
elif result.status == 'RETRY':
print('任务异常后正在重试')
elif result.status == 'STARTED':
print('任务已经开始被执行')
def set_task(num1,num2):
res = add.delay(num1, num2)
return res.id
# 批量提交、执行任务
# 实际情况可能会因为刚提交任务就提取,导致任务还在等待中,
# 因此为了更好的模拟可以在get_task中加入延迟
get_task(set_task(1,2))
get_task(set_task(2,3))
get_task(set_task(3,4))
延迟任务
# add_task.py
from tasks import add
from datetime import datetime, timedelta
# 获取当前utc时间+5秒
eta = datetime.utcnow() + timedelta(seconds=5)
# 创建延迟任务 五秒后执行
res = add.apply_async(args=[5, 6], eta=eta)
定时任务
# celerys.py
from celery import Celery
broker = 'redis://127.0.0.1:6379/0'
backend = 'redis://127.0.0.1:6379/1'
app = Celery('celery', broker=broker, backend=backend)
# 命令:
# celery -A add_tasks beat -l info
@app.task
def add(x, y):
return x + y
# add_tasks.py
from datetime import timedelta
from celery.schedules import crontab
from tasks import app
# 命令:
# celery -A celerys worker -l info -P eventlet
app.conf.beat_schedule = {
'add-task': {
# 要执行的方法所在的路径
'task': 'scripts.tasks.add',
# 每隔三秒启动一次
'schedule': timedelta(seconds=3),
# 参数
'args': (100, 200),
},
}
定时任务必须同时启动beat和worker(可以在两个终端)
celery -A add_tasks beat -l info
celery -A celerys worker -l info -P eventlet
- add_tasks:这个参数必须是app.conf.beat_schedule所在的py文件