在数据库中保存一个芹菜任务(用于重新运行)

时间:2019-09-05 23:01:11

标签: django celery celery-task

我们的工作流程当前是围绕旧版本的celery构建的,因此请记住事情已经不是最佳的。我们需要运行一个任务,并将该任务的记录保存在数据库中。如果该任务失败或挂起(它经常发生),我们希望重新运行,就像第一次运行一样。但是,这不应自动发生。需要根据故障的性质手动触发它,并且需要将结果记录在数据库中以做出决定(通过前端)。

我们如何在数据库中保存任务的完整记录,以便后续进程可以抓取记录并运行新的相同任务?当前实现将@task装饰函数的路径保存在DB中,作为TaskInfo模型的一部分。当需要重新运行任务时,我们在get_task()模型上有一个TaskInfo方法,该方法从数据库获取路径,使用getattr导入它,并使用另一个rerun()方法使用*args, **kwargs(也保存在数据库中)再次运行任务。

类似(TaskInfo模型实例上的方法):

def get_task(self):
    """Returns the task's decorated function, which can be delayed."""
    module_name, object_name = self.path.rsplit('.', 1)
    module = import_module(module_name)
    task = getattr(module, object_name)
    if inspect.isclass(task):
        task = task()
    # task = current_app.tasks[self.path]
    return task

 def rerun(self):
    """Re-run the task, and replace this one.

    - A new task is scheduled to run.
    - The new task's TaskInfo has the same parent as this TaskInfo.
    - This TaskInfo is deleted.
    """
    args, kwargs = self.get_arguments()
    celery_task = self.get_task()
    celery_task.delay(*args, **kwargs)
    defaults = {
        'path': self.path,
        'status': Status.PENDING,
        'timestamp': timezone.now(),
        'args': args,
        'kwargs': kwargs,
        'parent': self.parent,
    }
    TaskInfo.objects.update_or_create(task_id=celery_task.id, defaults=defaults)
    self.delete()

必须有一个更干净的解决方案才能将任务保存到数据库中以便以后重新运行,对吧?

1 个答案:

答案 0 :(得分:0)

最新版本的Celery(4.4.0)包含一个参数extended_result。您可以将其设置为True,然后celery_taskmeta中的表(默认名称为Result Backend Database)将存储任务的args and kwargs

这是一个演示:

app = Celery('test_result_backend')

app.conf.update(
    broker_url='redis://localhost:6379/10',
    result_backend='db+mysql://root:passwd@localhost/celery_toys',
    result_extended=True
)


@app.task(bind=True, name='add')
def add(self, x, y): 
    self.request.task_name = 'add'  # For saving the task name.
    time.sleep(5)
    return x + y 

使用记录在MySQL中的任务信息,您可以轻松地重新运行任务。