将类方法用作Celery任务

57 投票
5 回答
43850 浏览
提问于 2025-04-17 12:54

我正在尝试使用类的方法作为django-celery的任务,并通过@task装饰器来标记它们。类似的情况在这里被Anand Jeyahar提到过。大概是这样的:

class A:
    @task
    def foo(self, bar):
        ...

def main():
    a = A()
    ...
    # what i need
    a.foo.delay(bar) # executes as celery task 
    a.foo(bar) # executes locally

问题是,即使我像这样使用类的实例 a.foo.delay(bar),它还是提示说 foo 至少需要两个参数,这意味着 self 指针缺失了。

更多信息:

  • 我不能把类转换成模块,因为有继承关系。
  • 方法强烈依赖于类的成员,所以我不能把它们变成静态方法。
  • 用 @task 装饰器标记使得这个类本身成为一个任务,这样可以通过 run() 方法执行这些方法,使用某个参数作为选择方法的关键,但这并不是我想要的。
  • 创建类的实例并将其作为 self 参数传递给方法,这样执行方法的方式就变成了普通方法(也就是说,像平常那样测试),而不是celery任务。
  • 我试着找出如何动态注册任务,比如从构造函数中注册,但celery在工作进程之间共享代码,所以这似乎是不可能的。

谢谢你的帮助!

5 个回答

5

当你有了:

    a = A()

你可以这样做:

    A.foo.delay(a, param0, .., paramN)

谢谢!

11

Jeremy Satterfield 有一个简单明了的教程,教你如何写基于类的任务,如果你想这样做,可以在这里查看。

这个方法的关键在于扩展 celery.Task 类,并包含一个 run() 方法,像这样:

from celery import Task

class CustomTask(Task):
    ignore_result = True

    def __init__(self, arg):
        self.arg = arg

    def run(self):
        do_something_with_arg(self.arg)

然后你可以这样运行这个任务:

your_arg = 3

custom_task = CustomTask()
custom_task.delay(your_arg)

我不太确定 ignore_result = True 这一部分是否必要。

55

从3.0版本开始,Celery开始实验性地支持将方法作为任务来使用。

关于这方面的说明可以在celery.contrib.methods中找到,里面也提到了一些需要注意的事项:

https://docs.celeryproject.org/en/3.1/reference/celery.contrib.methods.html

请注意:从4.0版本开始,Celery不再支持contrib.methods

撰写回答