django + django-celery-beat搭建周期任务

前言

本文只研究界面配置管理周期任务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库

环境搭建

新建项目和app

新建一个项目(如果不会创建django项目的就看看其他资料),结构如下:
项目名:djangotask
在项目下新建一个app:xxx
django + django-celery-beat搭建周期任务_第1张图片

settings.py配置

  • 将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
    效果如下
    

    django + django-celery-beat搭建周期任务_第2张图片
    这时我们再看数据库是不是已经初始化好了表结构(里面有django和dj-celery-beat相关的表):
    django + django-celery-beat搭建周期任务_第3张图片

django-celery-beat 配置

  • 新建一个统筹celery配置的文件
    在项目目录djangotask/djangotask/目录下新建 celery.py,这个文件主要用来创建一个Celery对象,即第11行代码,然后加载Celery对象所需的配置即第14行
    django + django-celery-beat搭建周期任务_第4张图片

代码:

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()
  • 定义 Celery 对象所需的配置即 celeryconfig.py文件,这个文件里的内容也可以写到项目的 settings.py里面去,因为Celery 对象的配置文件位置可以在 celery.py 里进行指定;比起把这些配置写在settings.py里,我更喜欢单独存放;
    这个文件主要定义比如redis,序列化,worker等相关信息
    django + django-celery-beat搭建周期任务_第5张图片
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'},
}

  • 使能 celery.py
    注意:celery.py不会被框架自动加载进来,这里我们通过工程的init.py来把celery引进来 。 django + django-celery-beat搭建周期任务_第6张图片
    代码:
    from __future__ import absolute_import, unicode_literals
    from .celery import app as celery_app

定义任务

从上面的配置看,djcelery-beta会自动去扫描每个app目录下是否有 tasks.py 这么一个文件,这个文件就是我们编写任务具体内容的地方;我们在xxx app下新建一个tasks.py:
django + django-celery-beat搭建周期任务_第7张图片

代码:

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

createsuperuser 创建超级用户

创建用户主要作用是对任务进行管理,在manage.py目录下执行命令:

django + django-celery-beat搭建周期任务_第8张图片

python manage.py createsuperuser

测试

进入管理后台界面

启动django界面应用后访问 http://localhost:8000/admin/
输入刚刚的用户名密码
django + django-celery-beat搭建周期任务_第9张图片
这里我们进入“间隔任务”超链接,定义一个每分钟执行一次的任务;
django + django-celery-beat搭建周期任务_第10张图片
然后选择保存;
上面只是定义了一个周期计划,还要把周期计划和task进行绑定,我们进入“任务定义”超链接
django + django-celery-beat搭建周期任务_第11张图片
然后点击保存

启动beat

beta是一个生产者角色,是单独运行;从这里就可以看出,生产者完全不依赖django web界面,web界面作用是做配置!
idea开启一个命令行窗口,进入 manage.py 文件所在的位置,执行命令:

celery  -A djangotask beat -l info

django + django-celery-beat搭建周期任务_第12张图片
正常启动后,beat会定时的向redis发送消息:
django + django-celery-beat搭建周期任务_第13张图片

启动worker

再开启一个命令行窗口,进入 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

django + django-celery-beat搭建周期任务_第14张图片

资源

  • gitee

感兴趣的同学可以在 Gitee 下载本文代码

  • 参考

文章参考:https://www.cnblogs.com/liudinglong/p/13876124.html

  • celery文档

celery文档:DOC

cnblog资料: 资料

卓越笔记资料:资料

附:celery命令[通过如下命令可以获得命令列表]:

celery worker --help

你可能感兴趣的:(Python)