Django+Celery学习笔记4——django+celery+redis周期任务Crontabs设置

  引言

  前面已经讲过定时任务实例,使用的是基于intervals模式的周期任务。这只能满足一部分需求,如果是你想明天早上8点准时执行一个发送邮件的任务,这个时候需要设置一个未来的定时任务,Crontab模式就派上用场。

  参数

  默认参数:

crontab(minute='*', hour='*', day_of_week='*', day_of_month='*', month_of_year='*')

  这些参数可以设置表达式,表达稍微复杂的设置。默认值都是"*"星号,代表任意时刻。即crontab()相当与:含义是每天、每小时、每分钟执行一次任务。这说法太反人类语言习惯,简单说就是每1分钟执行一次任务。

   Crontab语法用五个段来定义时间,具体含义:

*     *   *   *    *  command to be executed
-     -    -    -    -
|     |     |     |     |
|     |     |     |     +----- day of week (0 - 6) (Sunday=0)
|     |     |     +------- month (1 - 12)
|     |     +--------- day of month (1 - 31)
|     +----------- hour (0 - 23)
+------------- min (0 - 59)

#所有的值都必须在相应的范围之内,否则视为无效。在填值区域内可以是*也可以是以”,”分隔的一组值。值可以是一个数据也可以是用连接符连起来的两个数(表示范围)。
#星号(*):代表所有可能的值,例如month字段如果是星号,则表示在满足其它字段的制约条件后每月都执行该命令操作。
#逗号(,):可以用逗号隔开的值指定一个列表范围,例如,“1,2,5,7,8,9”
#中杠(-):可以用整数之间的中杠表示一个整数范围,例如“2-6”表示“2,3,4,5,6”
#正斜线(/):可以用正斜线指定时间的间隔频率,例如“0-23/2”表示每两小时执行一次。同时正斜线可以和星号一起使用,例如*/10,如果用在minute字段,表示每十分钟执行一次。
注:日期的格式可以是星期,也可以是一个月中的天。假如两个都有值,则在这两个时间都会执行。

  具体如下:

#实例1:每1分钟执行一次command
* * * * * command

#实例2:每小时的第3和第15分钟执行
3,15 * * * * command

#实例3:在上午8点到11点的第3和第15分钟执行
3,15 8-11 * * * command

#实例4:每隔两天的上午8点到11点的第3和第15分钟执行
3,15 8-11 */2 * * command

#实例5:每个星期一的上午8点到11点的第3和第15分钟执行
3,15 8-11 * * 1 command

#实例6:每晚的21:30重启smb 
30 21 * * * /etc/init.d/smb restart

#实例7:每月1、10、22日的4 : 45重启smb 
45 4 1,10,22 * * /etc/init.d/smb restart

#实例8:每周六、周日的1 : 10重启smb
10 1 * * 6,0 /etc/init.d/smb restart

#实例9:每天18 : 00至23 : 00之间每隔30分钟重启smb 
0,30 18-23 * * * /etc/init.d/smb restart

#实例10:每星期六的晚上11 : 00 pm重启smb 
0 23 * * 6 /etc/init.d/smb restart

#实例11:每一小时重启smb 
* */1 * * * /etc/init.d/smb restart

#实例12:晚上11点到早上7点之间,每隔一小时重启smb 
* 23-7/1 * * * /etc/init.d/smb restart

#实例13:每月的4号与每周一到周三的11点重启smb 
0 11 4 * mon-wed /etc/init.d/smb restart

#实例14:一月一号的4点重启smb 
0 4 1 jan * /etc/init.d/smb restart

#实例15:每小时执行/etc/cron.hourly目录内的脚本
01   *   *   *   *     root run-parts /etc/cron.hourly

#注:run-parts这个参数了,如果去掉这个参数的话,后面就可以写要运行的某个脚本名,而不是目录名了
更多实例戳这里

  具体某个值:

上面提到这些参数的取值范围。我们可以直接设置某个值。例如:
crontab(minute=15)
即每小时的15分时刻执行一次任务。直接指定某个时刻。以此类推可以设置每天0点0分时刻执行任务的设置如下:
crontab(minute=0, hour=0)
当然,也可以设置多个值。例如0分和30分执行一次任务:
crontab(minute='0,30')
这里使用字符串,用逗号隔开数值。这里的逗号是表示多个表达式or逻辑关系。

  设置范围:

设置范围也是设置多个值,例如指定9点到12点每个小时的每分钟执行任务。
crontab(minute='*', hour='9-12')
这里*号是默认值,可以省略如下:
crontab(hour='9-12')
上面提到逗号是or逻辑关系。拓展一下,指定9点到12点和20点中每分钟执行任务:
crontab(hour='9-12,20')

  设置间隔步长:

假如我要设置1、3、5、7、9、11月份每天每分钟执行任务,按照上面的做法可以设置如下:
crontab(day_of_month='1,3,5,7,9,11')

观察数据可以发现,都是间隔2的步长。需要设置的数字比较少,若数字比较多显得很麻烦。例如我想每间隔2分钟就执行一次任务,要写30个数字想想就觉得很麻烦。crontab表达式还提供了间隔的处理,例如:
crontab(minute='*/2')

#每2个小时中每分钟执行1次任务
crontab(hour='*/2')

#每3个小时的0分时刻执行1次任务
#即[0,3,6,9,12,15,18,21]点0分
crontab(minute=0, hour='*/3')

#每3个小时或8点到12点的0分时刻执行1次任务
#即[0,3,6,9,12,15,18,21]+[8,9,10,11,12]点0分
crontab(minute=0, hour='*/3,8-12')

#每个季度的第1个月中,每天每分钟执行1次任务
#月份范围是1-12,每3个月为[1,4,7,10]
crontab(month_of_year='*/3')

#每月偶数天数的0点0分时刻执行1次任务
crontab(minute=0, hour=0, day_of_month='2-31/2')

#每年5月11号的0点0分时刻执行1次任务
crontab(0, 0, day_of_month='11', month_of_year='5')

  场景实例

  上面简单介绍了crontab的设置,具体设置请以下面为准。

  再次确认环境,这个很重要!!!

amqp==2.6.1
celery==4.3.0
Django==2.2.2
django-celery-beat==1.5.0
django-celery-results==1.1.2
django-timezone-field==3.1
eventlet==0.29.1
kombu==4.6.11
PyMySQL==0.9.3
python-crontab==2.5.1
pytz==2020.1
redis==3.2.1
vine==1.3.0

  环境不匹配,你将寸步难行。

  接下来配置几个主要的文件,setting.py文件配置如下:

LANGUAGE_CODE = 'zh-hans'
# 简体中文界面

# TIME_ZONE = 'Asia/Shanghai'
# 亚洲/上海时区

USE_I18N = True

USE_L10N = True

USE_TZ = False
# 不使用国际标准时间

TIME_ZONE ='UTC'
# TIME_ZONE = 'Asia/Shanghai'


# 设置 django-celery-beat 真正使用的时区
CELERY_TIMEZONE = TIME_ZONE

CELERY_ENABLE_UTC = True
# 是否启动时区设置

# 使用亚洲/上海时区
# CELERY_TIMEZONE = 'Asia/Shanghai'

# 解决时区问题 使用 timezone naive 模式,不存储时区信息,只存储经过时区转换后的时间
DJANGO_CELERY_BEAT_TZ_AWARE = False

# 使用0号数据库
CELERY_BROKER_URL = 'redis://127.0.0.1:6379/0'
# redis://:password@hostname:port/db_number
# CELERY_BROKER_URL = 'redis://:Abcdef@123456@192.168.1.102:6379/0'



# 每个 worker 最多执行3个任务就会被销毁,可防止内存泄露
CELERYD_MAX_TASKS_PER_CHILD = 3

# 使用redis作为中间件  定时任务调度器
CELERY_BROKER_TRANSPORT = 'redis'

# 自定义调度类,使用Django的ORM
CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler'

# 使用 database 作为结果存储
CELERY_RESULT_BACKEND = 'django-db'
# 任务结果,使用Django的ORM




# celery 内容等消息的格式设置
if os.name != "nt":
    # Mac and Centos
    # worker 启动命令:celery -A djangocelerydemo worker -l info
    CELERY_ACCEPT_CONTENT = ['application/json', ]
    CELERY_TASK_SERIALIZER = 'json'
    CELERY_RESULT_SERIALIZER = 'json'
else:
    # windows
    # pip install eventlet
    # worker 启动命令:celery -A djangocelerydemo worker -l info -P eventlet
    CELERY_ACCEPT_CONTENT = ['pickle', ]
    CELERY_TASK_SERIALIZER = 'pickle'
    CELERY_RESULT_SERIALIZER = 'pickle'


# CELERY_ACCEPT_CONTENT = ['application/json']
# # 设置任务接收的序列化类型
# CELERY_TASK_SERIALIZER = 'pickle'
# # 设置任务序列化方式
# CELERY_RESULT_SERIALIZER = 'pickle'
# # 设置结果序列化方式
#
# CELERY_ACCEPT_CONTENT = ['pickle', 'json']
# # 设置任务接收的序列化类型

  celery.py文件配置如下:

from __future__ import absolute_import, unicode_literals
import os

from celery import Celery, platforms
from django.utils.datetime_safe import datetime

# 获取当前文件夹名,即为该 Django 的项目名
project_name = os.path.split(os.path.abspath('.'))[-1]
project_settings = '%s.settings' % project_name
print(project_settings)

# 设置默认celery命令行的环境变量
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangocelerydemo.settings')


# 实例化 Celery,项目名称
app = Celery('djangocelerydemo')

# 解决时区问题
app.now = datetime.now

# 使用 django 的 settings 文件配置 celery
app.config_from_object('django.conf:settings', namespace='CELERY')

# 从所有app应用中加载任务模块tasks.py
app.autodiscover_tasks()

# 解决celery不能root用户启动的问题
platforms.C_FORCE_ROOT = True

# 任务过期时间
# CELERY_TASK_RESULT_EXPIRES = 60 * 60 * 24
# 有些情况下可以防止死锁
CELERYD_FORCE_EXECV = True

  项目下__init__.py文件的配置如下:

# 引入celery实例对象
from __future__ import absolute_import, unicode_literals
from djangocelerydemo.celery import app as celery_app

__all__ = ('celery_app',)


import pymysql
pymysql.install_as_MySQLdb()

  定时任务跟上篇文章一致如:

# Create your tasks here
from __future__ import absolute_import, unicode_literals

from djangocelerydemo.celery import app

@app.task
def plan_task_1():
    print("任务_1已运行!")
    return {"任务_1:success"}


@app.task
def plan_task_2():
    print("任务_2已运行!")
    return  {"任务_2:success"}

  项目结构

  上面配置好了,展示一下结构:

   周期任务设置

  先设置一个简单一点的,每隔2分钟执行一次,如:

   配置计划任务,如下:

  执行任务

  1.启动消费者

celery -A djangocelerydemo worker -l info -P eventlet

  2.启动心跳

celery -A djangocelerydemo  beat -l info

  心跳:

 

   消费:

   因为周期任务设置的是每天每2分钟执行一次计划任务,所以这里的时间间隔是2分钟,如图,44-46-48

  总结

  关于周期任务的设置先写到这里,后面还是有很多内容需要深入学习,有兴趣的朋友可以一起,加入学习交流群~

  

原文地址:https://www.cnblogs.com/liudinglong/p/13903441.html