6

我正在使用 celery beat 来安排一些任务。我可以使用 CELERY_TIMEZONE 设置来安排使用 crontab 计划的任务,它会在上述时区的计划时间运行。

但我希望能够在同一个应用程序(单个 django settings.py)中为不同的时区设置多个此类任务。我知道在计划任务时哪个任务需要在哪个时区运行。

是否可以为每个任务指定不同的时区?

我将 django (1.4) 与 celery (3.0.11) 和 django celery (3.0.11) 一起使用。

我查看了djcelery.schedulers.DatabaseScheduler该类,它是基类,但我无法弄清楚时区的使用方式和位置。我可以编写一个自定义调度程序,让每个作业在不同的时区运行吗?

谢谢,

4

4 回答 4

15

您可以在 celery 计划中实现单个任务的时区感知计划。这样,您可以通过为每个 celery 时间表指定单独的 now 函数,根据特定时区的本地时间运行任务(也调整为例如夏令时)

crontab支持nowfun参数指定用于检查是否应该运行的日期时间函数

import datetime
import pytz
nowfun = lambda: datetime.datetime.now(pytz.timezone('Europe/Berlin'))

在您的日程安排中,将此功能设置为日期时间功能

'periodic_task': {
    'task': 'api.tasks.periodic',
    'schedule': crontab(hour=6, minute=30, nowfun=nowfun)
}

这在欧洲中部时间每天早上 6.30 运行,调整为夏令时。

如果您多次使用该函数,请考虑创建一个助手

from functools import partial
cet_crontab = partial(crontab, nowfun=nowfun)
'periodic_task': {
    'task': 'api.tasks.periodic',
    'schedule': cet_crontab(hour=6, minute=30)
}

确保您已CELERY_ENABLE_UTC = False设置,否则 celery 会将您的日程表转换为 UTC。

于 2016-03-31T17:43:13.530 回答
1

我认为最简单的方法是使用装饰器mock

from mock import patch

@task
@patch.multiple(settings, CELERY_TIMEZONE='time_zone')
def my_task(*args):
    #do your staff

我还没有测试它,但它似乎是正确的。我希望我能帮助你:)

于 2014-02-17T12:39:45.273 回答
0

就我而言,我需要一个每次都会运行并从 db.xml 获取特定值的时区的函数。
我创建了一个新函数,它将接受一个变量并为我提供所需的时区。


def get_time(db_query: str) -> datetime.datetime:
    """Extract timezone from DB"""

    # get location from db
    timezone = 'get timezone for location'
    # return calculated datetime using timezone
    return datetime.datetime.now(pytz.timezone(timezone))


def custom_crontab(*args, **kwargs):
    """Create a custom crontab that will call get_time function and assign value to nowfun"""

    db_query = kwargs.pop("db_query")
    nowfun = get_time(db_query)
    kwargs['nowfun'] = nowfun
    # return the call to crontab
    return crontab(*args, **kwargs)


beat_schedule = {
    'periodic_task': {
        'task': 'main_job',
        'schedule': custom_crontab(minute=0, db_query='some_value'),
    }
}
于 2020-10-05T22:16:24.180 回答
-1

也许我误解了这个问题,但是如果你想在不同时区的某个时间运行任务,你能不能只用时区之间的小时差来抵消预定时间?例如,如果我想让一个任务在下午 5 点在两个不同的 TZ 中运行:

# settings.py
CELERY_TIMEZONE = "US/Eastern"

CELERYBEAT_SCHEDULE = { 
    # Task to run in EST
    'schedule-my-est-task': {
        'task': 'path.to.my.est.task',
        'schedule': crontab(minute=0, hour=17),
    },
    # Task to run in UTC - hour time is offset
    'schedule-my-utc-task': {
        'task': 'path.to.my.utc.task',
        'schedule': crontab(minute=0, hour=10), 
    },
}
于 2014-02-17T12:54:55.363 回答