Django Celery 结果将任务 ID 设置为人类可读的内容?

Posted

技术标签:

【中文标题】Django Celery 结果将任务 ID 设置为人类可读的内容?【英文标题】:Django Celery results set task id to something human readable? 【发布时间】:2018-03-10 06:51:02 【问题描述】:

很多天后,我有了一个工作 celery 和 celery beat 任务列表,结果使用 django_celery_results 存储。但是,当我查看表记录时,其中没有任何有用的信息。

是否可以将任务 ID 设置为人类可读的内容?

一个例子是使用演示任务,它返回一个不可读但不可读的任务 ID

tasks.py

@app.task
def test(a,b):
    return a + b

app.settings 中的调度程序

CELERYBEAT_SCHEDULE = 
    'test_task': 
        'task': 'home.tasks.test',
        'schedule': crontab(minute='*/1'),
    ,

【问题讨论】:

【参考方案1】:

简单的答案是否定的。task_id 属性是自动生成的。如果你向后看代码,生成 ID 的核心函数在 kombu.utils.uuid.uuid(..) 中,有趣的是它只是内置 uuid.uuid4(..) 的一个薄包装。

但是,如果您查看函数签名:

def uuid(_uuid=uuid4):
    """Generate unique id in UUID4 format.
    See Also:
        For now this is provided by :func:`uuid.uuid4`.
    """
    return str(_uuid())

..似乎可以提供您自己的生成 ID 的函数,只要它们是唯一的,它们就可以工作。从根本上说,您必须修补:celery.__init__.uuidcelery.utils.__init__.uuidcelery.utils.__init__.gen_unique_id

我认为您不能应用有价值的名称,因为调用此函数时不带任何参数来简单地返回一些独特的东西。

但是

如果您查看Task.applyTask.apply_async,则有一个未记录的参数task_id

这将允许您在调用/创建任务之前手动指定task_id,只要它们是全球唯一的,您仍然可以获得所有报告和指标。不幸的是,我没有看到任何简单的方法可以从结果中更改 task_id,以使其在事后更有用......有点让你的 UI 的文本框有点傻。


如果您的项目是为它设置的,您可以使用任务继承并以这种方式修改任务行为。理论上你应该可以覆盖applyapply_async 来注入任务的ID。

import time

from celery import Task

 class NamedTask(Task):
    id_gen = lambda: int(time.time() * 1000)


    def _gen_task_id(self):
        return 
            'task_id': '%s-%s' % (
                self.name,
                self.id_gen())

    def apply(self, *args, **kwargs):
        kwargs.update(self._gen_task_id())
        return Task.apply(self, *args, **kwargs)

    def apply_async(self, *args, **kwargs):
        kwargs.update(self._gen_task_id())
        return Task.apply_async(self, *args, **kwargs)



@task(base=NamedTask)
def add(x, y):
    return x + y

应该让你的任务 ID 看起来像:project.tasks.add-15073315189870

【讨论】:

您好,我不想更改任务 ID,这很好,我想知道是否可以向模型添加另一个字段,在其中我可以对其进行描述并在 django_celery_resutls 数据库视图中查看? @AlexW,你的问题应该已经很清楚了。因为现在问题本身的含义发生了变化。你的标题清楚地写着set task id to something human readable? 为混乱道歉,重新阅读我可以看到问题需要改进【参考方案2】:

实现一个自定义结果后端,它会覆盖_store_result 来决定将什么作为结果保存到数据库中。

根据您使用的后端,在 celery.backends 中查找相关类。

此示例扩展了 amqp 后端的结果。

class UsefulInfoBackend(AMQPBackend):
    def store_result(self, task_id, result, state,
                     traceback=None, request=None, **kwargs):
        result = super(UsefulInfoBackend, self).store_result(task_id, result, state,
                     traceback=None, request=None, **kwargs)
        result['useful_info'] = 'Very Useful! :)' # determine the rules for extraneous information here contains. 
        return result

在初始化 Celery 时,传递你的结果后端类。

celery.Celery(backend=UsefulInfoBackend)

【讨论】:

【参考方案3】:

试试:

@app.task(name="periodic_test")
def test(a, b):
    return a+b

这可能有助于在 UI 中查找任务状态,但 Celery 总是需要每个任务执行的唯一 ID。

【讨论】:

以上是关于Django Celery 结果将任务 ID 设置为人类可读的内容?的主要内容,如果未能解决你的问题,请参考以下文章

Django Celery Beat 和任务结果

Celery学习--- Celery 最佳实践之与django结合实现异步任务

Celery异步任务队列/周期任务+ RabbitMQ + Django

在 Django Celery 结果中使用临时文件

Celery分布式任务队列快速入门

如何在 Django 中等待芹菜任务的结果