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