簡介
celery beat
是一個調度器;它以常規的時間間隔開啟任務,任務將會在集群中的可用節點上運行。
默認情況下,入口項是從 beat_schedule
設置中獲取,但是自定義的存儲也可以使用,例如在 SQL 數據庫中存儲入口項。
你必須保證一個調度一次只被一個調度器運行,否則將會形成重復任務。使用中央集權的方式意味着調度不需要被同步,並且服務可以在沒有鎖的情況下操作。
時區
默認情況下,周期性任務使用 UTC 時區,但是你可以使用 timezone
設置修改時區。
時區設置成 Europe/London
的示例:
timezone='Europe/London'
這個設置必須添加到你的應用實例,或者通過直接配置(app.conf.timezone = 'Europe/London'
),或者如果你使用 app.config_from_object
方法配置的話你可以將其添加到你的配置模塊。查看配置這一節獲取關於配置選項的跟多信息。
默認的調度器會自動探測時區的更改(調度器存儲在 celerybeat-schedule
文件中),並且會重置調度器,但是其他的調度器可能沒有這么智能(例如:Django 數據庫調度器,下面有講到),這種情況下你必須自己重置調度器。
Django User:
Celery 建議並且兼容 Django1.4 中新引入的 USE_TZ
設置。
對於DJango用戶,TIME_ZONE
設置中聲明的時區將會被應用,或者你可以通過 timezone
設置為 celery 聲明一個自定義的時區。
當時區相關設置變更時數據庫調度器不會自動重置,所以你必須自己重置:
$ python manage.py shell >>> from djcelery.models import PeriodicTask >>> PeriodicTask.objects.update(last_run_at=None)
Entries
想要周期性的調用一個任務,你必須在beat調度列表中添加一項。
from celery import Celery from celery.schedules import crontab app = 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!'), ) @app.task def test(arg): print(arg)
在 on_after_configure
句柄上設置這些意味着當使用 test.s()
時我們不會在模塊級別對 app 求值。
add_periodic_task()
函數將會在 beat_schedule
設置中新增加一項,並且相同的設置也可以用來手動設置周期任務:
示例:每30秒運行一次 tasks.add
任務
app.conf.beat_schedule = { 'add-every-30-seconds': { 'task': 'tasks.add', 'schedule': 30.0, 'args': (16, 16) }, } app.conf.timezone = 'UTC'
注意:
如果你不清楚這些設置什么意思,請查看配置這一節。你可以直接在你的應用實例上設置這些選項,或者也可以使用一個單獨的配置模塊。
如果你給 args 提供一個單項的元組,別忘記構造器是逗號,不會一對括號。
為調度器使用 timedelta
意味着任務將以30秒為間隔發送(第一個任務將在 celery beat
啟動后的30秒運行,以后每運行完一個任務,隔30秒再運行另一個)。
Crontab
類似的調度器也有,查看 Crontab schedules
這一節。
就像 cron
,如果第一個任務在下一個任務到來之前沒有完成,那么任務可能重疊。如果這是你所關注的,你應該使用一個鎖策略來保證一次只有一個實例能運行(查看Ensuring a task is only executed one at a time
這一節)。
Available Fields
-
task
要執行的任務的名稱 -
schedule
執行的頻率。
這可以是一個表示秒數的整數,一個 timedelta
或者一個 crontab
。你還可以定義自己的調度器類型,只要擴展schedule
接口。
-
args
位置參數(list 或者 tuple) -
kwargs
關鍵字參數(dict) -
options
執行選項(dict)
這可以是apply_async()
支持的任何參數 -exchange, routing_key,expires
等等。 -
relative
如果relative
設置成真(True),timedelta
調度器依據時鍾調度。這意味着頻率將根據timedleta
的周期四舍五入到最近的秒,分,小時或者天。
默認情況下,relative
值為假(False),頻率沒有四舍五入,而是相對於 celery beat
啟動的時間。
Crontab schedules
如果你想要對什么時候執行任務有更多的控制,例如,一天中某個特殊時間或者一周中某天,你可以使用crontab
調度器類型:
from celery.schedules import crontab app.conf.beat_schedule = { # Executes every Monday morning at 7:30 a.m. 'add-every-monday-morning': { 'task': 'tasks.add', 'schedule': crontab(hour=7, minute=30, day_of_week=1), 'args': (16, 16), }, }
Crontab 表達式的語法非常靈活。
一些示例:
Example | Meaning |
---|---|
crontab() | 每分鍾執行 |
crontab(minute=0, hour=0) | 每天凌晨執行 |
crontab(minute=0, hour=’*/3’) | 每三個小時執行: midnight, 3am, 6am, 9am, noon, 3pm, 6pm, 9pm. |
crontab(minute=0,hour=’0,3,6,9,12,15,18,21’) | 同上 |
crontab(minute=’*/15’) | 每十五分鍾執行 |
crontab(day_of_week=’sunday’) | 星期天每分鍾執行 |
crontab(minute=’‘,hour=’‘, day_of_week=’sun’) | 同上 |
crontab(minute=’*/10’,hour=’3,17,22’, day_of_week=’thu,fri’) | 每十分鍾執行, 但是只在星期四、五的 3-4 am, 5-6 pm, and 10-11 pm |
crontab(minute=0, hour=’/2,/3’) | 每兩個小時及每三個小時執行,意思是: 除了下面時間的每個小時: 1am, 5am, 7am, 11am, 1pm, 5pm, 7pm, 11pm |
crontab(minute=0, hour=’*/5’) | 每五個小時執行。這意味着將在 3pm 而不是 5pm 執行 (因為 3pm 等於 24 小時制的 15, 能被 5 整除) |
crontab(minute=0, hour=’*/3,8-17’) | 每三個小時, 以及 (8am-5pm) 之間的小時執行 |
crontab(0, 0, day_of_month=’2’) | 每個月的第二天執行 |
crontab(0, 0, day_of_month=’2-30/3’) | 每個月的偶數天執行 |
crontab(0, 0,day_of_month=’1-7,15-21’) | 每個月的第一個和第三個星期執行 |
crontab(0, 0, day_of_month=’11’,month_of_year=’5’) | 每年五月份的第十一天執行 |
crontab(0, 0,month_of_year=’*/3’) | 每個季度的第一個月執行 |
查看 celery.schedules.crontab
這一節獲取更多的信息。
Solar schedules
如果你想任務依據日出、日落、黃昏、黎明時間來執行,你可以使用 solar
調度器類型:
from celery.schedules import solar app.conf.beat_schedule = { # Executes at sunset in Melbourne 'add-at-melbourne-sunset': { 'task': 'tasks.add', 'schedule': solar('sunset', -37.81753, 144.96715), 'args': (16, 16), }, }
參數很簡單: solar(event, latitude, longitude)
請確保為經度和緯度使用正確的符號:
Sign | Argument | Meaning |
---|---|---|
+ | latitude | North |
- | latitude | South |
+ | longtitude | East |
- | longtitude | West |
可能的事件類型有:
Event | Meaning |
---|---|
dawn_astronomical | 天不完全黑的時候執行。 太陽在地平線下18度 |
dawn_nautical | 地平線有充足的陽光並且可以看清一些事物; 形式化一點, 太陽在地平線下12度 |
dawn_civil | 有充足的陽光可以看清事物並且可以開始戶外活動; 形式化一點, 太陽在地平線下6度 |
sunrise | 太陽的上邊緣出現在東方地平線上時執行 |
solar_noon | 一天中太陽距離地平線最高的位置時執行 |
sunset | 傍晚太陽的上邊緣消失在西方地平線上時執行 |
dusk_civil | 黃昏的盡頭, 事物仍然可見並且可以看到一些星星。形式化一點, 太陽在地平線下6度 |
dusk_nautical | 形式化一點, 太陽在地平線下12度。事物已經看不清,並且地平線也看不清了 |
dusk_astronomical | 天完全黑時執行; 形式化一點, 太陽在地平線下18度 |
所有 solar
事件都使用 UTC 時間計算,因此不受你的 timezone 設置影響。
在極地區域,太陽可能不會每天都升起。這個調度器可以處理這種情況(即:當太陽沒有升起,sunrise
事件不會觸發)。只有 solar_noon
事件除外,這個事件是由太陽經過地球兩極縱分地球的圓環的時刻定義的,即使太陽在地平線下它也會天天觸發。
Twilight
定義為黎明到日出這段時間;以及日落到黃昏這段時間。依據你對 twilight
的定義(民用的、航海的或天文的),使用上述列表中的合適事件,你可以為你定義的twilight
觸發一個事件,並且可以指定讓事件在 twilight
開始還是結束的時刻觸發。
查看 celery.schedules.solar
獲取更多的信息。
Starting the Scheduler
啟動 celery beat
服務:
$ celery -A proj beat
你可以通過使能工作單元的 -B
選項將 beat
嵌入到你的工作單元中,如果你不會啟動多於一個工作單元,那么這是很便利的,但是這並不常用,並且也不推薦在生產環境使用:
$ celery -A proj worker -B
Beat 需要在一個本地數據庫文件(默認是 celerybeat-schedule
文件 )中保存任務的最后執行時間,所以需要有當前目錄的寫權限,或者你也可以為這個文件制定一個自定義的路徑:
$ celery -A proj beat -s /home/celery/var/run/celerybeat-schedule
注意:
使用 beat 守護進程,請查看相關文檔。
Using custom scheduler classes
自定義的調度器可以通過命令行中聲明(使用 --scheduler
參數)。
默認的調度器是 celery.beat.PersistentScheduler
,它將最后執行時間保存在本地一個 shelve
數據庫文件中。
有一個 django-celery-beat
擴展可以將調度保存到Django數據庫中,並且提供了一個方便的管理接口對運行的周期性任務進行管理。
安裝和使用這個擴展:
1. 使用 pip 安裝這個包:
$ pip install django-celery-beat
- 在你 Django 項目的配置文件
setting.py
中將django_celery_beat
添加到INSTALL_APPS
中
INSTALLED_APPS = ( ..., 'django_celery_beat', )
2. 應用 Django 數據遷移使得必要的數據庫表被創建
$ python manage.py migrate
3. 使用 django_celery_beat.schedulers:DatabaseScheduler
調度器:
$ celery -A proj beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
注意:
你也可以直接把他作為設置選項來添加
1. 訪問 Django-Admin 接口,並設置一些周期性的任務
轉自:https://blog.csdn.net/libing_thinking/article/details/78582609