本文只研究界面配置管理周期任务cron场景,如果想要学习异步任务和硬编码cron周期任务的请搜索其他资料。
极力推荐另一好文: 知乎; 本文代码下载: Gitee
天下小白苦python久矣,各种模块版本不兼容在最近一次搭建一个定时任务的过程中体现的淋漓尽致;
在网上查了很多资料,真心写的能让入门小白看明白的文章凤毛麟角;
最开始想用celery和django-celery来搭建周期任务的,网上各种写法的都有看得头晕;
有的说celery什么版本后不支持widows;这个特性让我感到很震惊,毕竟还是有很大部分开发还是用的widows作为操作系统来开发的吧!
在经过大量的资料查阅和经历各种版本不匹配后,我最终选择了 django-celery-beat这个框架来完成周期任务的搭建;
第一是这个框架支持在界面配置任务的执行周期(逻辑和定时器解耦),很符合我最开始的预期;
第二是在界面配置task对于的cron表达式能够立即生效,不用重启;
最开始的时候我在寻求一种解决方案:
服务端只启动一个(django既做界面展示角色,也做消息生产角色),然后消费端启动多个,中间用redis作为消息队列;
经过大量查资料,结果证明在python 和celery的组合拳场景下不是我想的那样,而是:
1、django界面角色只能说是周期任务的入口,操作数据库的入口
(在周期硬编码的情况下是不是连django前台页面都可以不用启动?这个有待确认)
2、生产者需要单独启动(一个叫beat的组件)
3、消费者单独启动,即worker
这样设计我估计是为了解耦,扩展;
但是这样的设计就会出现一个问题,同一份代码要在不同的地方启动多次:django启动一个,beat启动一个,worker启动n个;
这个跟现有比较流行的任务调度框架比如xxl-job的思想还是不一样的;
首先需要理解这一点差异,才会更好的接受他的一些操作;
在python世界里,版本不对寸步难行(pip其实可以做的更好)
名称 | 版本号 | 备注 |
---|---|---|
python | 3.7.9 | |
django | 2.2 | django和python版本关系 |
django-celery-beat | 2.2.1 | 安装了django-celery-beat 会自动把 celery(5.1.2)安装好 |
django_celery_results | 2.2.0 | |
mysqlclient | 2.0.3 | dj-celery-beta数据库操作时需要 |
redis | 3.5.3 | |
eventlet | 0.31.0 | 可选,windows下运行celery 4以后版本,还需额外安装eventlet库 |
新建一个项目(如果不会创建django项目的就看看其他资料),结构如下:
项目名:djangotask
在项目下新建一个app:xxx
将xxx app 和 django_celery_beat app 添加到 INSTALLED_APPS 变量
INSTALLED_APPS = [
...省略了已经默认有的一些app..
"xxx",
'django_celery_beat',
]
配置数据库,我这里用的是本地mysql
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'task',
'USER': 'root',
'PASSWORD': 'root',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
执行数据库migrate,因为django-celery-beat带了一些表结构
在manage.py所在目录分别执行:
python manage.py magemigrations
python manage.py migrate
效果如下
代码:
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
# 设置django环境
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangotask.settings')
# 创建一个Celery app
app = Celery('djangotask')
# 使用CELERY_ 作为前缀,在celeryconfig.py中写配置
app.config_from_object('djangotask.celeryconfig')
# 发现任务文件每个app下的task.py
app.autodiscover_tasks()
from __future__ import absolute_import
# broker 设置
broker_url = 'redis://127.0.0.1:6379/0'
# 指定 Backend
# CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/1'
result_backend = 'django-db'
# 使用django_celery_beat插件用来动态配置任务
beat_scheduler = 'django_celery_beat.schedulers:DatabaseScheduler'
# 指定时区,默认是 UTC
timezone = 'Asia/Shanghai'
# celery 序列化与反序列化配置
task_serializer = 'pickle'
result_serializer = 'pickle'
accept_content = ['pickle', 'json']
task_ignore_result = True
# 有些情况下可以防止死锁
CELERYD_FORCE_EXECV = True
# celery beat配置(周期性任务设置)
enable_utc = False
# 官方用来修复CELERY_ENABLE_UTC=False and USE_TZ = False 时时间比较错误的问题;
# 详情见:https://github.com/celery/django-celery-beat/pull/216/files
DJANGO_CELERY_BEAT_TZ_AWARE = False
# 路由(哪个任务放入哪个队列)
task_routes = {
'xxx.tasks.add': {'queue': 'queue1'},
'xxx.tasks.mul': {'queue': 'queue2'},
}
from __future__ import absolute_import, unicode_literals
from .celery import app as celery_app
从上面的配置看,djcelery-beta会自动去扫描每个app目录下是否有 tasks.py 这么一个文件,这个文件就是我们编写任务具体内容的地方;我们在xxx app下新建一个tasks.py:
代码:
from __future__ import absolute_import, unicode_literals
from celery import shared_task
@shared_task
def add(x, y):
print("invoke add #####################################")
return x + y
@shared_task
def mul(x, y):
print("invoke add #####################################")
print("invoke mul")
return x * y
创建用户主要作用是对任务进行管理,在manage.py目录下执行命令:
python manage.py createsuperuser
启动django界面应用后访问 http://localhost:8000/admin/
输入刚刚的用户名密码
这里我们进入“间隔任务”超链接,定义一个每分钟执行一次的任务;
然后选择保存;
上面只是定义了一个周期计划,还要把周期计划和task进行绑定,我们进入“任务定义”超链接
然后点击保存
beta是一个生产者角色,是单独运行;从这里就可以看出,生产者完全不依赖django web界面,web界面作用是做配置!
idea开启一个命令行窗口,进入 manage.py 文件所在的位置,执行命令:
celery -A djangotask beat -l info
再开启一个命令行窗口,进入 manage.py 文件所在的位置,执行命令:
# Linux下测试,启动Celery
Celery -A djangotask worker -l info
# Windows下测试,启动Celery
Celery -A djangotask worker -l info -P eventlet
# 如果Windows下Celery不工作,输入如下命令
Celery -A djangotask worker -l info --pool=solo
感兴趣的同学可以在 Gitee 下载本文代码
文章参考:https://www.cnblogs.com/liudinglong/p/13876124.html
celery文档:DOC
cnblog资料: 资料
卓越笔记资料:资料
附:celery命令[通过如下命令可以获得命令列表]:
celery worker --help