首先我们有一个这样的需求
我们为了能在Web
端口动态的添加定时任务,本次来调研一下Celery 4.x
在Django
框架下
要如何去动态添加定时任务。
我们新建一个Django项目
安装最新的Django
pip install django
然后创建项目
django-admin startproject
项目名称
执行结果:
django-admin startproject django_con .
安装celery:
pip3 install django-celery
pip3 install -U Celery
pip3 install "celery[librabbitmq,redis,auth,msgpack]"
pip3 install django-celery-beat # 用于动态添加定时任务
pip3 install django-celery-results
pip3 install redis
接下来安装相关依赖:
amqp==2.5.2
anyjson==0.3.3
asgiref==3.2.7
billiard==3.6.3.0
celery==4.4.2
cffi==1.14.0
cryptography==2.9.2
Django==3.0.6
django-celery==3.3.1
django-celery-beat==2.0.0
django-celery-results==1.2.1
django-timezone-field==4.0
dnspython==1.16.0
eventlet==0.25.2
greenlet==0.4.15
importlib-metadata==1.6.0
kombu==4.6.8
monotonic==1.5
pycparser==2.20
python-crontab==2.4.2
python-dateutil==2.8.1
pytz==2020.1
redis==3.5.1
six==1.14.0
sqlparse==0.3.1
vine==1.3.0
zipp==3.1.0
测试celery
创建celery目录
第一步:在Django
项目中创建一个celery_tasks
文件夹,然后再创建tasks.py
图下:
第二步:编写tasks.py
内容为图下:
from celery import Celery
# 使用redis作为broker
app = Celery('celery_tasks.tasks', broker='redis://192.168.196.135:6379/8')
# 创建任务函数
@app.task
def my_task():
print("任务函数正在执行....")
第三步:celery
第一个参数设定一个名字,第二个参数设定一个中介broker
,在这我是用redis
座位中介。my_task
函数是我编写的一个任务函数,通过加上装饰器app.task
,让它注册道broker
队列中。
我们进入项目的根目录,执行命令:celery -A celery_tasks.tasks worker -l info
图下:
调用任务
我们接下来测试功能,创建一个任务,加入道任务队列中,提供worker
执行。
进入python
终端,执行下面代码:
[root@python_env django_cron]# python3 manage.py shell
from celery_tasks.tasks import my_task
# 调用一个任务函数,将会返回一个AsyncResult对象,这个对象可以用来检查任务的状态或者获得任务的返回值。
my_task.delay()
输出结果: <AsyncResult: 647b2589-95d2-45c9-a9a7-0b5530caf249>
然后返回worker
终端界面,查看一下任务的执行,图下:
现在就可以看到已经收到了任务,并且打印出了信息。
储存结果
要是我们想跟踪任务的状态,Celery
就需要将结果保存到一个地方。
有几种方式可以保存:SQLAlchemy、Django ORM、Memcached、 Redis、RPC (RabbitMQ/AMQP)
加入我们仍然使用Redis座位储存的结果,任务结果储存配置我们通过Celery
的backend
参数来设定。我们要将tasks
模块修改:
from celery import Celery
# 使用redis作为broker以及backend
app = Celery('celery_tasks.tasks',
broker='redis://192.168.196.135:6379/8',
backend='redis://192.168.196.135:6379/9')
# 创建任务函数
@app.task
def my_task(a, b):
print("任务函数正在执行....")
return a + b
我给Celery
增加了backend
参数,指定redis
作为结果存储,并将任务函数修改为两个参数,并且有返回值。
借来下我们执行调用一下这个任务看看。
from celery_tasks.tasks import my_task
# 传递参数至任务中
ret = my_task.delay(10,20)
# 查询返回值的结果
ret.result
输出结果: 30
# 查看是否执行失败
ret.failed()
输出结果: False
再来看worker
的执行情况,图下:
可以看到celery
任务已经执行成功了。
这只是一个开始,下一步要看看如何添加定时的任务。
优化Celery目录
上面直接将Celery
的应用创建、配置、tasks
任务全部写在了一个文件,这样在后面项目越来越大,也是不方便的。下面来拆分一下,并且添加一些常用的参数 图下:
创建Celery应用的文件 celery.py
from celery import Celery
from celery_tasks import celeryconfig
import os
# 为celery设置环境变量
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_con.settings")
## 创建celery app
app = Celery('celery_tasks')
# 从单独的配置模块中加载配置
app.config_from_object(celeryconfig)
# 设置app自动加载任务
app.autodiscover_tasks([
'celery_tasks',
])
配置Celery的参数文件 celeryconfig.py
# 设置结果存储
CELERY_RESULT_BACKEND = 'redis://192.168.196.135:6379/9'
# 设置代理人broker
BROKER_URL = 'redis://192.168.196.135:6379/8'
# celery 的启动工作数量设置
CELERY_WORKER_CONCURRENCY = 20
# 任务预取功能,就是每个工作的进程/线程在获取任务的时候,会尽量多拿 n 个,以保证获取的通讯成本可以压缩。
CELERYD_PREFETCH_MULTIPLIER = 20
# 非常重要,有些情况下可以防止死锁
CELERYD_FORCE_EXECV = True
# celery 的 worker 执行多少个任务后进行重启操作
CELERY_WORKER_MAX_TASKS_PER_CHILD = 100
# 禁用所有速度限制,如果网络资源有限,不建议开足马力。
CELERY_DISABLE_RATE_LIMITS = True
tasks 任务文件 tasks.py
from celery_tasks.celery import app
# 创建任务函数
@app.task
def my_task(a, b, c):
print("任务函数正在执行....")
return a + b + c
接下来我们开始安装使用定时任务
安装 django-celery-beat
pip3 install django-celery-beat
配置 django-celery-beat
# 安装应用 django_celery_beat
INSTALLED_APPS = [
'django_celery_beat', # 安装 django_celery_beat
...
]