动态添加芹菜周期性任务

时间:2017-12-06 10:47:19

标签: python flask celery

是否可以动态向芹菜添加定期任务?

我使用的是Flask,而不是django,我正在构建一个应该允许用户通过Web界面定义周期性任务的应用程序。

我尝试过使用Celery 4.1中的Periodic Tasks,但是要添加新任务我必须停止celery服务器,更改配置(即使通过python完成),然后重新启动它。也许有一种方法可以动态加载配置(无需重新启动它)?

我已经考虑过每5分钟重新启动一次芹菜服务的crontab。但它似乎非常反对。除了其他原因,因为我想使用芹菜的原因是不使用crontab。

有没有人对此有所了解?

ps:我知道another similar question,但是从2012年开始。我希望自那时起事情发生了变化,即在v4.1中引入节拍

2 个答案:

答案 0 :(得分:1)

这适用于Celery 4.0.1+和Python 2.7以及Redis

from celery import Celery
import os, logging
logger = logging.getLogger(__name__)
current_module = __import__(__name__)

CELERY_CONFIG = {
    'CELERY_BROKER_URL': 
     'redis://{}/0'.format(os.environ.get('REDIS_URL', 'localhost:6379')),
  'CELERY_TASK_SERIALIZER': 'json',
}


celery = Celery(__name__, broker=CELERY_CONFIG['CELERY_BROKER_URL'])
celery.conf.update(CELERY_CONFIG)

我通过以下方式定义作业:

job = {
    'task': 'my_function',               # Name of a predefined function
    'schedule': {'minute': 0, 'hour': 0} # crontab schedule
    'args': [2, 3],
    'kwargs': {}
}
然后我定义了一个这样的装饰器:

def add_to_module(f):
    setattr(current_module, 'tasks_{}__'.format(f.name), f)
    return f

我的任务是

@add_to_module
def my_function(x, y, **kwargs):
    return x + y

然后添加一个动态添加任务的功能

def add_task(job):
    logger.info("Adding periodic job: %s", job)
    if not isinstance(job, dict) and 'task' in jobs:
        logger.error("Job {} is ill-formed".format(job))
        return False
    celery.add_periodic_task(
        crontab(**job.get('schedule', {'minute': 0, 'hour': 0})),
        get_from_module(job['task']).s(
            enterprise_id,
            *job.get('args', []),
            **job.get('kwargs', {})
        ),
        name = job.get('name'),
        expires = job.get('expires')
    )
    return True


def get_from_module(f):
    return getattr(current_module, 'tasks_{}__'.format(f))

在此之后,您可以将add_task函数链接到URL,并让它们从当前模块中的函数创建任务

答案 1 :(得分:0)

为此,您可以使用redBeat。基于redbeat GitHub:

RedBeat是Celery Beat Scheduler,它在Redis中存储计划的任务和运行时元数据。

用于创建任务:

import tasks #celery defined task class 
from redbeat import RedBeatSchedulerEntry as Entry
entry = Entry(f'urlCheck_{key}', 'tasks.urlSpeed', repeat, args=['GET', url, timeout, key], app=tasks.app)
entry.save()
entry.key

删除任务:

import tasks #celery defined task class 
from redbeat import RedBeatSchedulerEntry as Entry
entry = Entry.from_key(key, app=tasks.app) #key from previous step
entry.delete()

,您可以使用一个示例:https://github.com/hamedsh/redBeat_example