周期性任务 — Python 文档

来自菜鸟教程
Celery/docs/latest/userguide/periodic-tasks
跳转至:导航、​搜索

周期性任务

简介

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 一样,如果第一个任务在下一个任务之前没有完成,任务可能会重叠。 如果这是一个问题,您应该使用锁定策略来确保一次只能运行一个实例(参见例如 确保一次只执行一个任务 )。

可用字段

  • 任务

    要执行的任务的名称。

  • 日程

    执行频率。

    这可以是整数形式的秒数、timedeltacrontab。 您还可以通过扩展schedule的接口来定义您自己的自定义时间表类型。

  • 参数

    位置参数(listtuple)。

  • 夸格斯

    关键字参数 (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=0,
hour='0,3,6,9,12,15,18,21')
和以前一样。
crontab(minute='*/15') 每 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 点、下午 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') 在每个月的第二天执行。
crontab(0, 0,
day_of_month='2-30/2')
在每个偶数日执行。
crontab(0, 0,
day_of_month='1-7,15-21')
在每月的第一周和第三周执行。
crontab(0, 0, day_of_month='11',
month_of_year='5')
每年5月11日执行。
crontab(0, 0,
month_of_year='*/3')
在每个季度的第一个月每天执行。

有关更多文档,请参阅 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

笔记

要守护beat,请参阅Daemonization


使用自定义调度程序类

可以在命令行(--scheduler 参数)上指定自定义调度程序类。

默认调度程序是 celery.beat.PersistentScheduler,它只是在本地 shelve 数据库文件中跟踪上次运行时间。

还有 :pypi:`django-celery-beat` 扩展,它在 Django 数据库中存储计划,并提供一个方便的管理界面来管理运行时的周期性任务。

要安装和使用此扩展:

  1. 使用 pip 安装包:

    $ pip install django-celery-beat
  2. django_celery_beat 模块添加到 Django 项目'settings.py 中的 INSTALLED_APPS

    INSTALLED_APPS = (
        ...,
        'django_celery_beat',
    )

    请注意,模块名称中没有破折号,只有下划线。

  3. 应用 Django 数据库迁移,以便创建必要的表:

    $ python manage.py migrate
  4. 使用 django_celery_beat.schedulers:DatabaseScheduler 调度程序启动 celery beat 服务:

    $ celery -A proj beat -l INFO --scheduler django_celery_beat.schedulers:DatabaseScheduler

    注意:您也可以直接将其添加为 :setting:`beat_scheduler` 设置。

  5. 访问 Django-Admin 界面来设置一些周期性任务。