引言
前面已经讲过定时任务实例,使用的是基于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@[email protected]: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
总结
关于周期任务的设置先写到这里,后面还是有很多内容需要深入学习,有兴趣的朋友可以一起,加入学习交流群~