本文首發(fā)于公眾號(hào):Hunter后端原文鏈接:celery筆記七之周期/定時(shí)任務(wù)及crontab定義
periodic task,即為周期,或者定時(shí)任務(wù),比如說每天晚上零點(diǎn)零分需要運(yùn)行一遍某個(gè)函數(shù),或者每隔半小時(shí)運(yùn)行一遍該函數(shù),都是這種任務(wù)的范疇。
在第一篇筆記的時(shí)候我們就介紹過 celery 的組件構(gòu)成,其中有一個(gè)組件叫做 beat,就是我們定時(shí)任務(wù)的調(diào)度器。
【資料圖】
所有的定時(shí)任務(wù)都由 beat 發(fā)出,這種情況下,你必須確保在同一個(gè)時(shí)間點(diǎn)只有一個(gè) beat 任務(wù)調(diào)度器在運(yùn)行,假設(shè)有兩個(gè) beat 同時(shí)在運(yùn)行,那么在檢測(cè)定時(shí)任務(wù)的時(shí)候,系統(tǒng)的任務(wù)就可能會(huì)被重復(fù)發(fā)起、調(diào)用、執(zhí)行。
beat_schedule 定義beat 啟動(dòng)crontab介紹1、beat_schedule 定義我們來定義兩個(gè)定時(shí)任務(wù),一個(gè)是 blog.tasks.add,定義為每隔 30s 執(zhí)行一次,現(xiàn)在晚上11點(diǎn)45分,我們定義每天11點(diǎn)50分執(zhí)行一次。
在進(jìn)行這些操作前,我們還需要對(duì)時(shí)區(qū)有一些設(shè)置,因?yàn)槲覀冊(cè)O(shè)置的晚上11點(diǎn)是北京時(shí)間,而 Django 和 celery 默認(rèn)是格林威治時(shí)間。
時(shí)區(qū)設(shè)置
我們使用 Django 系統(tǒng),一些配置在 settigns.py 中定義,詳情可以見前幾篇筆記的 celery 與 Django 系統(tǒng)使用。
關(guān)于時(shí)區(qū),Django 系統(tǒng)和 celery 的時(shí)區(qū)我們都設(shè)置成北京時(shí)間:
# settings.py# django 時(shí)區(qū)設(shè)置TIME_ZONE = "Asia/Shanghai"USE_TZ = False# celery 時(shí)區(qū)設(shè)置 CELERY_TIMEZONE = "Asia/Shanghai"CELERY_ENABLE_UTC = FalseDJANGO_CELERY_BEAT_TZ_AWARE = False
定時(shí)任務(wù)定義
接下來,我們定義定時(shí)任務(wù):
from celery.schedules import crontabapp.conf.beat_schedule = { "add-every-30-seconds": { "task": "blog.tasks.add", "schedule": 30, "args": (16, 16), }, "schedule_test_add": { "task": "blog.tasks.minus", "schedule": crontab(minute="50", hour="23"), },}
定時(shí)任務(wù)的定義是我們通過 app.conf.beat_schedule 來操作,一個(gè)任務(wù)我們定義一個(gè) name 作為 key
在每個(gè) task 下,分別有以下選項(xiàng):
task:指向我們定義的任務(wù),比如我們這個(gè)是指向 blog application 下 tasks.add 任務(wù)
schedule:定時(shí)任務(wù)的策略,如果直接定義一個(gè)整數(shù),比如定義的 add-every-30-seconds task 的這個(gè)參數(shù)定義為 30,就會(huì)每隔30s 執(zhí)行一次
而如果使用 crontab() 函數(shù),則可以更自由的定義到每個(gè)月,每周,每天,每時(shí)每秒,在示例中我們定義 minute="50", hour="23" 表示每天 23點(diǎn)50分執(zhí)行一次
更詳細(xì)的策略我們下面再詳細(xì)介紹。
args:定時(shí)任務(wù)的參數(shù),比如 add() 函數(shù),我們每隔 30s 執(zhí)行一次,給定的兩個(gè)參數(shù)是 (16, 16),對(duì)應(yīng) add(x, y) 輸入的兩個(gè)值
2、beat 啟動(dòng)beat 的啟動(dòng)方式和 worker 啟動(dòng)方式一致,將 worker 改成 beat 即可:
celery -A hunter beat -l INFO
也可以指定日志的輸出文件:
celery -A hunter beat -l INFO --logfile=/Users/hunter/python/celery_log/beat.log
當(dāng)我們啟動(dòng) beat 的時(shí)候,會(huì)發(fā)現(xiàn)啟動(dòng)的文件夾下會(huì)有一個(gè)名為 celerybeat-schedule.db 的文件,這個(gè)是 beat 保存在本地的上一次任務(wù)運(yùn)行的時(shí)間的數(shù)據(jù),我們也可以指定該文件的輸出地址:
celery -A hunter beat -l INFO -s /Users/hunter/python/celery_log/celerybeat-schedule
如果我們需要運(yùn)行定時(shí)任務(wù),我們需要額外啟動(dòng)兩個(gè)服務(wù),一個(gè)是 beat,一個(gè)是 worker
一般來說我們會(huì)先啟動(dòng) worker,再啟動(dòng) beat,這樣 beat 有一些立即發(fā)出的任務(wù)就可以直接被 worker 接收然后運(yùn)行。
3、crontab介紹我們使用 crontab() 函數(shù)制定定時(shí)任務(wù)的時(shí)間策略,比如每天運(yùn)行一次,或者指定周幾運(yùn)行都可以實(shí)現(xiàn)。
如果你之前接觸過 Linux 服務(wù)器上的 crontab 服務(wù),那么就不用擔(dān)心理解它的使用方式,如果沒有,我們可以看看下面官方文檔對(duì)著的介紹。
在 celery 里,crontab 函數(shù)通過 from celery.schedules import crontab 引入,在 beat_schedule 的定義里作為 schedule 的值,這個(gè)前面給過一個(gè)示例。
crontab 接受五個(gè)參數(shù):
minute 表示分鐘,接收整數(shù)或者整數(shù)列表,范圍在0-59,或者字符串表示配置的時(shí)間模式hour 表示小時(shí),接收整數(shù)或者整數(shù)列表,范圍在0-23,或者接收字符串表示配置的時(shí)間模式day_of_week 表示周幾,接收整數(shù)或者整數(shù)列表,范圍在0-6,其中周日是0,周六是6,或者接收字符串表示配置的時(shí)間模式day_of_month 表示一個(gè)月的第幾天,接收整數(shù)或者整數(shù)列表,范圍在1-31,或者接收字符串表示配置的時(shí)間模式month_of_year 表示一年的第幾個(gè)月,接收整數(shù)或者整數(shù)列表,范圍在1-12,或者接收字符串表示配置的時(shí)間模式minute 和 hour
minute 和 hour 直接指向一天的某個(gè)時(shí)間點(diǎn),所以,這兩個(gè)參數(shù)相當(dāng)于是必填,除非是某些特殊的情況,比如默認(rèn)的每分鐘執(zhí)行一次:
crontab()
上面的命令,什么參數(shù)也不傳,表示的是每隔一分鐘執(zhí)行一次
如果我們想指定特定的時(shí)間點(diǎn),比如每天晚上11點(diǎn)23分執(zhí)行一次:
crontab(minute=23, hour=23)
如果我們想指定某一些分鐘,比如分別在 23點(diǎn)11分,23點(diǎn)25分,23點(diǎn)44分鐘分別執(zhí)行一次,可以如下操作:
crontab(minute="11,25,44", hour=23)
如果是上面這種沒有特殊關(guān)系的時(shí)間點(diǎn),我們可以這樣通過逗號(hào)分隔連接起來,如果是有特殊關(guān)系的,比如說,每隔一分鐘,或者每隔三分鐘,我們可以通過 */n
的方式來連接。
23點(diǎn)之內(nèi),每隔三分鐘執(zhí)行一次函數(shù)可以如下操作:
crontab(minute="*/3", hour=23)
這里的每隔 n 分鐘,其實(shí)是 n 的倍數(shù),比如說 */3
就是在 0,3,6,9,12... 等這些分鐘數(shù)上執(zhí)行。
還有一種是范圍內(nèi)的操作方式,比如說,23點(diǎn)的 10-20分鐘內(nèi)每分鐘執(zhí)行一次:
crontab(minute="10-20", hour=23)
那么上面的方式合并起來可不可以,比如說在23點(diǎn)的第5分鐘,11分鐘,51分鐘,31-40分鐘,并且每隔兩分鐘執(zhí)行一次
也可以實(shí)現(xiàn),把上面的方式都添加在一起,就是一個(gè)或的操作:
crontab(minute="5,11,51,10-20,*/2", hour=23)
對(duì)于分鐘的這些操作,對(duì)于小時(shí)數(shù)是同樣生效的,不過范圍在 0-23 之間,比如說指定0點(diǎn),5點(diǎn),8點(diǎn),16點(diǎn)的零分執(zhí)行一次,那就是:
crontab(minute=0, hour="0,5,8,16")
如果是每個(gè)小時(shí)執(zhí)行一次呢,就是:
crontab(minute=0, hour="*/1")# 當(dāng) n = 1 的時(shí)候 1可以省略,即為crontab(minute=0, hour="*")
hour 的范圍參數(shù)和指定的小時(shí)點(diǎn),像 minute 參數(shù)一樣,也是可以或操作功能那樣生效的。
day_of_week
day_of_week 參數(shù)表示周幾,當(dāng)我們使用這個(gè)參數(shù)的時(shí)候,minute 和 hour 參數(shù)是同樣生效的,這里我們只演示 day_of_week 參數(shù)的作用,小時(shí)和分鐘我們都定為 0點(diǎn)0分。
當(dāng)我們不指定這個(gè)參數(shù)的時(shí)候,即為每天,只有指定了這個(gè)參數(shù)的時(shí)候,定義的周幾才會(huì)生效,比如我們定義在周一,周三,周五三天的零點(diǎn)執(zhí)行一次:
crontab(minute=0, hour=0, day_of_week="1,3,5")
這里,周日是0,周一是1,周二是2,依次類推。
day_of_week 的參數(shù)還可以使用英文的簡(jiǎn)寫,這里不做介紹,因?yàn)槲覀€(gè)人認(rèn)為還是直接使用數(shù)字方便一點(diǎn)。
另一個(gè)需要注意的是,day_of_week 也可以使用 */n
的形式,但是周幾總共只有7個(gè),所以我這里推薦直接用數(shù)字寫出來。
day_of_month
表示一個(gè)月的第幾天,范圍是1-31。
其使用方法和 minute、hour 使用的方式是一致的,使用范圍和 */n
的形式都可以實(shí)現(xiàn)。
比如我們想實(shí)現(xiàn)在1號(hào),5號(hào),7號(hào),8號(hào),以及每個(gè)偶數(shù)日的零點(diǎn)零分執(zhí)行一次,可以這樣操作:
crontab(minute=0, hour=0, day_of_month="1,5,7,8,*/2")
month_of_year
表示一年的某幾個(gè)月,范圍是1-12。
和前面的使用方式一致,如果需要使用,只有12個(gè)數(shù)字,還是推薦直接定義。
如果想獲取更多后端相關(guān)文章,可掃碼關(guān)注閱讀:
關(guān)鍵詞: