Django Celery定时任务和时间设置
继上篇文章Celery分布式队列入门,我们接着使用celery在Django项目中执行定时任务。
1.Celery加入定时任务
Celery除了可以异步执行任务之外,还可以定时执行任务。在实例代码的基础上写个测试方法:
上篇文章原先的tasks.py修改如下:
from celeryProject import celery_app from celery.schedules import crontab import time @celery_app.on_after_configure.connect def setup_periodic_tasks(sender, **kwargs): # Calls test('hello') every 10 seconds. sender.add_periodic_task(10.0, test.s('hello'), name='add every 10') # Calls test('world') every 30 seconds sender.add_periodic_task(30.0, test.s('world'), expires=10) # Executes every Monday morning at 7:30 a.m. sender.add_periodic_task( crontab(hour=7, minute=30, day_of_week=1), test.s('Happy Mondays!'), ) @celery_app.task def test(arg): print(arg) @celery_app.task def sendmail(email): print('start send email to %s' % email) time.sleep(5) # 休息5秒 print('success') return True celery_app.conf.timezone = 'UTC'
该代码是设定了三个定时任务。
上篇文章启动celery是使用worker。但worker不能启动定时任务。启动方式如下:
1)先确保中间人是否打开,我使用redis作为中间人。可参考Redis在CentOS7和Windows的安装过程。
2)进入django项目的根目录执行如下代码启动celery的worker:
celery -A celeryProject worker -l info
其中,celeryProject是我的django项目名称。如下图,看红色方框下的tasks列表。

有两个任务,其中一个myapp.tasks.sendmail是上篇文章添加的异步处理任务。myapp.tasks.test是本次的定时任务。
3)同样在django项目的根目录下再打开一个命令行界面,执行如下代码:
celery -A myapp.tasks beat -l info #注意,这里-A后面的项目位置要写tasks.py文件所在的位置
这个beat是检查定时任务,并启动定时任务丢给worker执行。如下图:

上面的窗口是beat,下面的窗口是worker。可看到print的信息在worker中输出。

我们甚至不用打开Django项目的服务器,就可以执行定时任务。
还可以通过配置文件方式指定定时和计划任务,此时的配置文件如下:
tasks.py修改如下:
from celeryProject import celery_app from celery.schedules import crontab import time @celery_app.task def test(arg): print(arg) @celery_app.task def sendmail(email): print('start send email to %s' % email) time.sleep(5) # 休息5秒 print('success') return True celery_app.conf.beat_schedule = { 'add-every-10-seconds': { # 计划任务 'task': 'myapp.tasks.test', #任务路径 'schedule': 10.0, #设定时间 'args': ('hello',), #传入参数 }, 'add-every-30-seconds': { 'task': 'myapp.tasks.test', 'schedule': 30.0, 'args': ('world',), }, 'add-every-Monday-morning-7:30': { 'task': 'myapp.tasks.test', 'schedule':crontab(hour=7, minute=30, day_of_week=1), 'args': ('Happy Mondays!',), }, } celery_app.conf.timezone = 'UTC'
同样启动worker和beat结果和第一种方式一样。以上定时任务可以写入配置文件中(settings.py)。更多详细的内容请参考:http://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html#crontab-schedules。
修改代码,需要重启Celery的worker和beat。
2.更复杂的定时配置
不知道大家有没有注意到,上面有个定时任务用到了crontab功能,利用此功能,我们可以个性化定制任务执行时间。
from celery.schedules import crontab celery_app.conf.beat_schedule = { 'add-every-Monday-morning-7:30': { 'task': 'myapp.tasks.test', 'schedule':crontab(hour=7, minute=30, day_of_week=1), 'args': ('Happy Mondays!',), }, }
上面的代码意思是每周1的早上7.30执行tasks.test任务
其中,crontab()实例化的时候没设置任何参数,都是使用默认值。crontab一共有7个参数,常用有5个参数分别为:
minute:分钟,范围0-59;
hour:小时,范围0-23;
day_of_week:星期几,范围0-6。以星期天为开始,即0为星期天。这个星期几还可以使用英文缩写表示,例如“sun”表示星期天;
day_of_month:每月第几号,范围1-31;
month_of_year:月份,范围1-12。
a、默认参数
这些参数可以设置表达式,表达稍微复杂的设置。默认值都是"*"星号,代表任意时刻。即crontab()相当与:
crontab(minute='*', hour='*', day_of_week='*', day_of_month='*', month_of_year='*')
含义是每天、每小时、每分钟执行一次任务。这说法太反人类语言习惯,简单说就是每1分钟执行一次任务。
b、具体某个值
上面提到这些参数的取值范围。我们可以直接设置某个值。例如:
crontab(minute=15)
即每小时的15分时刻执行一次任务。直接指定某个时刻。以此类推可以设置每天0点0分时刻执行任务的设置如下:
crontab(minute=0, hour=0)
当然,也可以设置多个值。例如0分和30分执行一次任务:
crontab(minute='0,30')
这里使用字符串,用逗号隔开数值。这里的逗号是表示多个表达式or逻辑关系。
c、设置范围
设置范围也是设置多个值,例如指定9点到12点每个小时的每分钟执行任务。
crontab(minute='*', hour='9-12')
这里*号是默认值,可以省略如下:
crontab(hour='9-12')
上面提到逗号是or逻辑关系。拓展一下,指定9点到12点和20点中每分钟执行任务:
crontab(hour='9-12,20')
d、设置间隔步长
假如我要设置1、3、5、7、9、11月份每天每分钟执行任务,按照上面的做法可以设置如下:
crontab(day_of_month='1,3,5,7,9,11')
观察数据可以发现,都是间隔2的步长。需要设置的数字比较少,若数字比较多显得很麻烦。例如我想每间隔2分钟就执行一次任务,要写30个数字想想就觉得很麻烦。crontab表达式还提供了间隔的处理,例如:
crontab(minute='*/2') crontab(minute='0-59/2') #效果等同上面
这个/号不是除以的意思。相当与range的第3个参数,例如:
range(0, 59+1, 2)
差不多crontab表达式就这些,多举几个例子:
#每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')
上面能满足你绝大多数定时任务需求了,甚至还能根据潮起潮落来配置定时任务, 具体看 http://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html#solar-schedules
浙公网安备 33010602011771号