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

 

posted on 2019-08-17 15:16  xufat  阅读(1278)  评论(0)    收藏  举报

导航

/* 返回顶部代码 */ TOP