django + celery + redis 实现定时任务

前言

前段时间,工作中有个要求,是将原本的定时任务,改成使用celery实现。原本项目中的定时任务是使用的apscheduler。但是django与celery做定时的教程,网上比较少,且版本对应不上,最后根据网上的教程+仔仔细细看了好多遍celery官方文档,终于跑通。

现在做一个快速实现django+celery定时任务的教程/记录。
关于这三个组件的基础知识及安装就不赘述了。直接进入配置。

版本

Django==3.1.4
celery==5.0.5
redis==3.5.3

思路步骤

配置celery定时任务的思路和步骤主要为

  1. 创建celery实例
  2. 配置任务
  3. 编写任务函数
  4. 启动woker和beat
  5. 存储结果

目录层级(供参考)

django_demo                    # 项目根目录
    ├── scheduler              # 这是一个app
    │   ├── __init__.py
    │   ├── celery.py            # 实例化celery并指定config
    │   ├── config.py           # celery的配置文件
    │   └── tasks.py             # 任务函数
  1. celery.py

from __future__ import absolute_import
from celery import Celery

app = Celery("scheduler", broker="redis://:12345@localhost:6379/1", backend="redis://:12345@localhost:6379/2", include=["scheduler.tasks"])

app.config_from_object("scheduler.config")

此文件用于实例化celery,并指定broker和backend为redis(可写入配置文件)
include是指向task文件
app.config_from_object()指定celery的配置

  1. config.py

from __future__ import absolute_import

from datetime import timedelta
CELERY_TIMEZONE = "Asia/Shanghai"
CELERY_ENABLE_UTC = True

CELERYBEAT_SCHEDULE = {
    "test": {                                 #任务名,用于开发人员识别
        "task": "scheduler.tasks.test",       #task指向任务函数
        "schedule": timedelta(seconds=2),     #调度时间 还可以使用crontab
        "args": ()                            #没有参数可以不写
    },
}

此文件可以写一些celery的配置,以及通过CELERYBEAT_SCHEDULE将定时任务加载。
定时的时间可以使用crontab。
例如:crontab(hour="*/24") 表示每24小时执行一次
也可以指定时间,详情参照crontab的使用方法

  1. tasks.py

from scheduler.celery import app

@app.task()
def test():
    print("hello")
    return None

import app一定是从实例化的celery.py中导入的。如果实例化文件不叫celery.py,或者对象不叫app,需要对应改变。
任务函数需要使用@app.task()进行装饰。如果无需返回值,可以不写return。

  1. 终端命令启动worker及beat

此处需要开2个终端,或者在liunx中一起写入shell脚本中均可

celery -A scheduler.celery beat -l info  # 启动beat
celery -A scheduler.celery worker -l info

scheduler.celery 是根据目录及文件所定的,请根据自己的项目进行改变
-l info : 运行时输出日志

如果是在windows下进行启动则worker命令需要替换为

-P eventlet :是windows下启动worker, 其他系统删除
(如果提示eventlet没有就使用pip安装下eventlet)

celery -A scheduler.celery worker -l info -P eventlet  # windows下启动worker

以上是关于celery定时任务的简单配置




在工作项目中,代码需要尽可能的简洁,配置需要放在同一个总的配置文件中,并且项目分为开发和线上环境,所以最后我的django配置是这样的:

django_demo                        # 项目根目录
    ├── settings
    |    ├── base.py                #基础设置
    |    ├── develop.py          #开发环境设置          
    ├── scheduler              # 这是一个app
    │   ├── __init__.py
    │   ├── celery.py            # 实例化celery并指定config
    │   └── tasks.py             # 任务函数

我将上方的config.py中的配置分别写进了django中的settings文件中。

1. settings:

  • develop.py:
BROKER_URL = redis_url
CELERY_RESULT_BACKEND = redis_url

开发环境下,配置开发所用的broker 和 backend,注意变量名不能写错,否则celery识别不出
redis_url是我们的redis端口,我这里是写在了其他地方,方便对所有的组件进行管理。
也可以这样写:

BROKER_URL = "redis://:12345@localhost:6379/1"
CELERY_RESULT_BACKEND = "redis://:12345@localhost:6379/1"
  • base.py:
    此处我将任务的调度写入了项目的base配置。

    # celery配置及任务配置
    CELERY_TIMEZONE = "Asia/Shanghai"
    CELERY_ENABLE_UTC = True
    
    CELERYBEAT_SCHEDULE = {
      "job1": {
          "task": "scheduler.tasks.job1",
          "schedule": crontab(minute=0, hour=3),
      },
      "job2": {
          "task": "scheduler.tasks.job2",
          "schedule": crontab(hour="*/24"),
      },
    }

2. celery.py

from __future__ import absolute_import

import os

from celery import Celery

profile = os.environ.setdefault("PROFILE", "production")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", f"demo.settings.{profile}")

app = Celery("scheduler", include=["scheduler.jobs"])
app.config_from_object("django.conf:settings")
  1. 这里为了方便开发与线上进行区别,首先进行了整体环境的设置。
  2. profile 以及 os.environ.setdefault 都是对项目环境进行的设置.
  3. celery的主体还是app与app.config_from_object.

可以发现,我这里的Celery()中的变量少了,更简洁了,这是因为,我把这些元素都写入了django的settings中了,celery实例化的时候,会根据我配置的"django.conf:settings"进行查找对应的值。

3.jobs.py

from scheduler.celery import app

@app.task()
def job1():
    pass

def job2():
    pass

总结:

celery实现定时任务还是比较容易实现的。主要是celery的实例化,配置与任务配置,任务函数,三个部分组成。关于配置可以随机应变,写到任何地方都可以。关键是三个文件在引用的时候,不用弄混就行了。
一个是实例化celery的时候,app.config_from_object() 注意写对我们的配置路径
一个是配置文件中的配置定时任务时的任务函数路径
一个是任务函数的装饰器@app.task()一定是实例化celery中的对象。

django + celery + redis 实现定时任务_第1张图片
展示下定时任务正在执行的输出。
local是启动的worker
local2是启动的beat

beat终端中,运行起来的时候,会一直打印发送任务成功。
worker会一直输出任务接收成功,并返回return值及任务函数中的输出。

参考

你可能感兴趣的:(django + celery + redis 实现定时任务)