Сельдерей бить - разные часовые пояса за задачу

Я использую сельдерей, чтобы наметить некоторые задачи. Я могу использовать параметр CELERY_TIMEZONE для планирования задач с помощью расписания crontab, и оно запускается в запланированное время в указанном часовом поясе.

Но я хочу иметь возможность настроить несколько таких задач для разных часовых поясов в одном приложении (один файл django settings.py). Я знаю, какая задача должна выполняться в каком часовом поясе, когда она запланирована.

Можно ли указать разные часовые пояса для каждой из задач?

Я использую django (1.4) с сельдереем (3.0.11) и django celery (3.0.11).

Я посмотрел на djcelery.schedulers.DatabaseScheduler класс и его базовый класс, но я не могу понять, как и где используется часовой пояс. Могу ли я написать собственный планировщик, который может запускать каждое задание в другом часовом поясе?

Спасибо,

3 ответа

Вы можете достичь расписания отдельных задач в расписании сельдерея с учетом часового пояса. Таким образом, вы можете запустить задачу в соответствии с местным временем в определенном часовом поясе (также настраивая, например, переход на летнее время), указав отдельную функцию now для каждого расписания сельдерея.

crontab поддерживает nowfun аргумент для указания функции datetime, которая будет использоваться для проверки, должна ли она выполняться

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 установить, в противном случае сельдерей конвертирует ваши графики в UTC.

Я думаю, что самый простой способ сделать это - использовать декоратор с mock

from mock import patch

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

Я еще не проверял это, но это кажется правильным. Я надеюсь, что я помог тебе:)

В моем случае мне нужна была функция, которая будет запускаться каждый раз и получать часовой пояс для определенного значения из db.
Я создал новую функцию, которая примет переменную и предоставит мне нужный часовой пояс.


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'),
    }
}

Может быть, я неправильно понимаю проблему, но если вы хотите запускать задачи в определенное время в разных часовых поясах, не могли бы вы просто сместить запланированное время на разницу часов между часовыми поясами? Например, если я хотел, чтобы задача выполнялась в 17:00 в двух разных 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), 
    },
}
Другие вопросы по тегам