周期性任务 — Python 文档
周期性任务
简介
celery beat是一个调度器; 它定期启动任务,然后由集群中的可用工作节点执行。
默认情况下,条目取自 :setting:`beat_schedule` 设置,但也可以使用自定义存储,例如将条目存储在 SQL 数据库中。
您必须确保一次只有一个调度程序正在运行一个调度,否则最终会出现重复的任务。 使用集中式方法意味着不必同步计划,并且服务可以在不使用锁的情况下运行。
时区
周期性任务计划默认使用 UTC 时区,但您可以使用 :setting:`timezone` 设置更改使用的时区。
一个示例时区可以是 欧洲/伦敦 :
timezone = 'Europe/London'
必须将此设置添加到您的应用程序中,通过直接使用 (app.conf.timezone = 'Europe/London'
) 对其进行配置,或者将其添加到您的配置模块(如果您已使用 app.config_from_object
进行设置)。 有关配置选项的更多信息,请参阅 Configuration。
默认调度器(将调度存储在 celerybeat-schedule
文件中)会自动检测时区已更改,因此会重置调度本身,但其他调度器可能没有那么聪明(例如,Django 数据库调度器,见下文),在这种情况下,您必须手动重置计划。
Django 用户
Celery 推荐并兼容 Django 1.4 中引入的新 USE_TZ
设置。
对于 Django 用户,将使用 TIME_ZONE
设置中指定的时区,或者您可以使用 :setting:`timezone` 设置单独为 Celery 指定自定义时区。
当时区相关设置更改时,数据库调度程序不会重置,因此您必须手动执行此操作:
$ python manage.py shell
>>> from djcelery.models import PeriodicTask
>>> PeriodicTask.objects.update(last_run_at=None)
Django-Celery 仅支持 Celery 4.0 及以下版本,对于 Celery 4.0 及以上版本,请执行以下操作:
$ python manage.py shell
>>> from django_celery_beat.models import PeriodicTask
>>> PeriodicTask.objects.update(last_run_at=None)
参赛作品
要定期调用任务,您必须在节拍计划列表中添加一个条目。
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)
@app.task
def add(x, y):
z = x + y
print(z)
在 @on_after_configure
处理程序中设置这些意味着我们不会在使用 test.s()
时在模块级别评估应用程序。 请注意,@on_after_configure
是在应用程序设置后发送的,因此在应用程序声明的模块之外的任务(例如 在位于 celery.Celery.autodiscover_tasks()
的 tasks.py 文件中)必须使用稍后的信号,例如 @on_after_finalize
。
@add_periodic_task()
函数会在后台的:setting:`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 计划 的部分。
与 cron 一样,如果第一个任务在下一个任务之前没有完成,任务可能会重叠。 如果这是一个问题,您应该使用锁定策略来确保一次只能运行一个实例(参见例如 确保一次只执行一个任务 )。
可用字段
任务
要执行的任务的名称。
日程
执行频率。
这可以是整数形式的秒数、
timedelta
或crontab
。 您还可以通过扩展schedule
的接口来定义您自己的自定义时间表类型。参数
位置参数(
list
或tuple
)。夸格斯
关键字参数 (
dict
)。选项
执行选项(
dict
)。这可以是
apply_async()
– exchange、routing_key、expires 等支持的任何参数。相对的
如果 relative 为真,则
timedelta
计划是“按时钟”安排的。 这意味着频率将根据timedelta
的周期四舍五入到最接近的秒、分、小时或日。默认情况下,relative 为 false,频率不会四舍五入,而是相对于 celery beat 开始的时间。
Crontab 时间表
如果您想更好地控制任务的执行时间,例如,一天中的特定时间或一周中的某天,您可以使用 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 表达式的语法非常灵活。
一些例子:
例子 | 意义 |
crontab()
|
每分钟执行一次。 |
crontab(minute=0, hour=0)
|
每天午夜执行。 |
crontab(minute=0, hour='*/3')
|
每三个小时执行一次:午夜、凌晨 3 点、早上 6 点、早上 9 点、中午、下午 3 点、下午 6 点、晚上 9 点。 |
|
和以前一样。 |
crontab(minute='*/15')
|
每 15 分钟执行一次。 |
crontab(day_of_week='sunday')
|
在星期日每分钟 (!) 执行一次。 |
|
和以前一样。 |
|
每十分钟执行一次,但仅限于周四或周五的凌晨 3-4 点、下午 5-6 点和晚上 10-11 点。 |
crontab(minute=0, hour='*/2,*/3')
|
每隔偶数小时执行一次,并且每小时可被 3 整除。 这意味着:每小时 除外 :1am、5am、7am、11am、1pm、5pm、7pm、11pm |
crontab(minute=0, hour='*/5')
|
执行可被 5 整除的小时。 这意味着它在下午 3 点而不是 5 点触发(因为 3 点等于 24 小时时钟值“15”,可被 5 整除)。 |
crontab(minute=0, hour='*/3,8-17')
|
每小时执行一次,可被 3 整除,并在办公时间(上午 8 点至下午 5 点)每小时执行一次。 |
crontab(0, 0, day_of_month='2')
|
在每个月的第二天执行。 |
|
在每个偶数日执行。 |
|
在每月的第一周和第三周执行。 |
|
每年5月11日执行。 |
|
在每个季度的第一个月每天执行。 |
有关更多文档,请参阅 celery.schedules.crontab
。
太阳能时间表
如果你有一个任务需要按照日出、日落、黎明或黄昏来执行,你可以使用 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)
请务必使用正确的纬度和经度符号:
标志 | 争论 | 意义 |
+
|
latitude
|
北 |
-
|
latitude
|
南 |
+
|
longitude
|
东 |
-
|
longitude
|
西 |
可能的事件类型有:
事件 | 意义 |
dawn_astronomical
|
在天空不再完全黑暗的那一刻执行。 这是太阳在地平线以下 18 度的时候。 |
dawn_nautical
|
当有足够的阳光让地平线和一些物体可以区分时执行; 正式地,当太阳在地平线以下 12 度时。 |
dawn_civil
|
当有足够的光线可以区分物体时执行,以便开始户外活动; 正式地,当太阳在地平线以下 6 度时。 |
sunrise
|
当早晨太阳的上边缘出现在东部地平线时执行。 |
solar_noon
|
当当天太阳位于地平线上方时执行。 |
sunset
|
当傍晚太阳的后缘消失在西部地平线上时执行。 |
dusk_civil
|
在民用暮光结束时执行,此时物体仍可区分并且一些恒星和行星可见。 正式地,当太阳在地平线以下 6 度时。 |
dusk_nautical
|
当太阳在地平线以下 12 度时执行。 物体不再可区分,地平线不再是肉眼可见的。 |
dusk_astronomical
|
在天空变得完全黑暗的那一刻执行; 正式地,当太阳在地平线以下 18 度时。 |
所有太阳事件均使用 UTC 计算,因此不受时区设置的影响。
在极地地区,太阳可能不会每天升起或落下。 调度程序能够处理这些情况(即,sunrise
事件不会在太阳不升起的那一天运行)。 一个例外是 solar_noon
,正式定义为太阳穿过天体子午线的时刻,即使太阳在地平线以下也会每天发生。
黄昏被定义为黎明和日出之间的时期; 在日落和黄昏之间。 您可以根据您对暮光的定义(民用、航海或天文),以及是否希望事件发生在暮光之初或结束时,使用上面列表中的适当事件,根据“暮光之城”来安排事件.
有关更多文档,请参阅 celery.schedules.solar
。
启动调度程序
启动 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
使用自定义调度程序类
可以在命令行(--scheduler
参数)上指定自定义调度程序类。
默认调度程序是 celery.beat.PersistentScheduler
,它只是在本地 shelve
数据库文件中跟踪上次运行时间。
还有 :pypi:`django-celery-beat` 扩展,它在 Django 数据库中存储计划,并提供一个方便的管理界面来管理运行时的周期性任务。
要安装和使用此扩展:
使用 pip 安装包:
$ pip install django-celery-beat
将
django_celery_beat
模块添加到 Django 项目'settings.py
中的INSTALLED_APPS
:INSTALLED_APPS = ( ..., 'django_celery_beat', )
请注意,模块名称中没有破折号,只有下划线。
应用 Django 数据库迁移,以便创建必要的表:
$ python manage.py migrate
使用
django_celery_beat.schedulers:DatabaseScheduler
调度程序启动 celery beat 服务:$ celery -A proj beat -l INFO --scheduler django_celery_beat.schedulers:DatabaseScheduler
注意:您也可以直接将其添加为 :setting:`beat_scheduler` 设置。
访问 Django-Admin 界面来设置一些周期性任务。