任务调度:Celery神器
任务调度:Celery神器
celery是一个强大的分布式任务队列,任务队列一般用于线程或计算机之间分配工作的一种机制。它的架构组成如下图:

- 任务模块
包含异步任务与定时任务。异步任务通常在业务逻辑中被触发,并被发往任务队列;定时任务由celery beat进程周期性地将任务发往任务队列。
- 消息中间件broker
broker,即为任务调度队列,接收任务生产者发来的任务消息,将任务存入队列。celery本身不提供任务队列,推荐使用RabbitMQ和Redis。
- 任务执行单元worker
worker实时监控消息队列,获取调度的任务,并执行。
- 任务结果存储backend
backend用于存储任务的执行结果,通消息中间件一样,存储可使用RabbitMQ,Redis,MongoDB等。
安装
$ pip install 'celery'
$ pip install eventlet ,如果window系统下安装的是celery4版本并运行报错,需要安装此包,后续启动worker时加上一个参数-P eventlet
请确保Redis以正确安装,并启动Redis服务。
创建Celery实例
# task.py
# -*- coding:utf-8 -*-
from celery import Celery
from celery.schedules import crontab
from datetime import timedelta
# 配置模块
class celeryconfig():
# 指定消息中间件用 redis
BROKER_URL = 'redis://127.0.0.1:6379/7'
# 指定存储用 redis
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/8'
# 指定时区,默认是 UTC
CELERY_TIMEZONE = 'Asia/Shanghai'
# 任务调度
CELERYBEAT_SCHEDULE = {
'add_every_10_seconds': {
# 指定任务
'task': 'tasks.add',
# 每 10 秒执行一次
'schedule': timedelta(seconds=10),
# 任务函数参数
'args': (2, 32)
}
}
# 创建一个Celery实例app,名称为my_task
app = Celery('my_task')
# 通过 Celery 实例加载配置模块
app.config_from_object(celeryconfig)
# 你的任务
@app.task
def add(x, y):
print("正在执行任务文件...")
return x + y
- 执行任务
$ celery -A tasks worker --loglevel=info -P eventlet
-------------- celery@LAPTOP-P97PCAUQ v5.2.0 (dawn-chorus)
--- ***** -----
-- ******* ---- Windows-10-10.0.19041-SP0 2021-11-10 10:11:31
- *** --- * ---
- ** ---------- [config]
- ** ---------- .> app: demo:0x1a7655f3b20
- ** ---------- .> transport: redis://127.0.0.1:6379/7
- ** ---------- .> results: redis://127.0.0.1:6379/8
- *** --- * --- .> concurrency: 8 (eventlet)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
其中 -A 指定了Celery实例的未知,实例在tasks.py文件中, Celery 会自动在该文件中寻找 Celery 对象实例;--loglevel 指定了日志级别,默认为warning;-P 解决Window系统下celery4版本运行的报错
- 发布任务
$ celery -A tasks beat
celery beat v5.2.0 (dawn-chorus) is starting.
__ - ... __ - _
LocalTime -> 2021-11-10 10:18:17
Configuration ->
. broker -> redis://127.0.0.1:6379/7
. loader -> celery.loaders.app.AppLoader
. scheduler -> celery.beat.PersistentScheduler
. db -> celerybeat-schedule
. logfile -> [stderr]@%WARNING
. maxinterval -> 5.00 minutes (300s)
上述执行任务与发布任务分别在tasks.py文件目录下执行,当启动执行任务没有报错,再执行发布任务,此时在切换控制台窗口到worker的启动窗口,会看到执行任务的日志信息
[2021-11-10 10:19:11,128: INFO/MainProcess] Task tasks.add[6edc02df-3055-41f0-91ce-bb7e8f2aeb28] received
[2021-11-10 10:19:11,129: WARNING/MainProcess] 正在执行任务文件...
[2021-11-10 10:19:11,131: INFO/MainProcess] pidbox: Connected to redis://127.0.0.1:6379/7.
定时任务
Celery除了可以执行异步任务,也支持执行周期性任务(Periodic Tasks),或者说是定时任务, Celery Beat 进程通过读取配置文件的内容,周期性地将定时任务发往任务队列。
再来看一个定时任务例子,项目结构如下:
celery_demo # 项目根目录
├── celery_app # 存放 celery 相关文件
│ ├── __init__.py
│ ├── celeryconfig.py # 配置文件
│ ├── task1.py # 任务文件 1
│ └── task2.py # 任务文件 2
__init__.py 代码如下:
# -*- coding:utf-8 -*-
from celery import Celery
# 创建Celery实例
app = Celery('demo')
# 通过Celery实例加载配置模块
app.config_from_object('celery_app.celeryconfig')
celeryconfig.py 代码如下:
# -*- coding:utf-8 -*-
from datetime import timedelta
from celery.schedules import crontab
# Broker and Backend
BROKER_URL = 'redis://127.0.0.1:6379/7' # 带密码 redis://:passwd@127.0.0.1:6379/7
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/8'
# 指定时区,不指定默认为 'UTC'
CELERY_TIMEZONE = 'Asia/Shanghai'
# import
CELERY_IMPORTS = {
'celery_app.task1',
'celery_app.task2',
}
# schedules
CELERYBEAT_SCHEDULE = {
'add_every_20_seconds': {
'task': 'celery_app.task1.add',
'schedule': timedelta(seconds=20), # 每 20 秒执行一次
'args': (2, 3) # 任务函数参数
},
'multiply_at_some_time': {
'task': 'celery_app.task2.multiply',
'schedule': crontab(hour=9, minute=50), # 每天早上 9 点 50 分执行一次
'args': (2, 3) # 任务函数参数
}
}
task1.py 代码如下:
# -*- coding:utf-8 -*-
from celery_app import app
@app.task
def add(x, y):
return x + y
task2.py 代码如下:
# -*- coding:utf-8 -*-
from celery_app import app
@app.task
def multiply(x, y):
return x * y
在项目的根目录下执行下面命令:
# 执行任务(窗口1)
celery_demo $ celery -A celery_app worker --loglevel=info -P eventlet
# 发布任务(窗口2)
celery_demo $ celery -A celery_app beat
- 结尾
在生产环境中,我们通常会使用 Supervisor 来控制 Celery Worker 进程。
- 相关资料
官⽅⼿册:https://docs.celeryproject.org/en/stable/
中⽂翻译:https://www.celerycn.io
Github:https://github.com/celery/celery
- 参考资料:
【异步任务神器 Celery 简明笔记】:https://fast.v2ex.com/t/327228

浙公网安备 33010602011771号