【问题标题】:using super in celery task在芹菜任务中使用超级
【发布时间】:2017-05-15 16:51:32
【问题描述】:

我有一些基类,例如:

class Auto(object):
    _year = None
    _base_price = None

    @classmethod
    def calculate_price(cls):
        return cls._base_price + 5000 * (2016 - cls._year)

class BMW(Auto):
    _year = 2015
    _base_price = 40000

    @celery.task(filter=task_method,
             name='queue_name',
             base=basetask(), bind=True)
    def calculate_price(self):
        super(BMW, self).calculate_price()

所以,我的问题在于最后一行代码,它引发了: TypeError: super(type, obj): obj must be an instance or subtype of type

我试图删除bind=True 并尝试使用它,但没有任何结果。任何想法如何解决这个问题?

更新: 在哪里

celery = Celery(...)

所以,我正在使用像 app.task 这样的装饰器

【问题讨论】:

  • 通常会看到与函数一起使用的任务装饰器,而不是方法。我并不是说它不能完成,但它很少见。有很多资源讨论如何将您的任务行为放在一个类中(例如blog.balthazar-rouberol.com/celery-best-practices),但任务装饰器仍然应用于普通函数。也许您可以通过这种方式简化您的设计。同样相关:*.com/questions/9250317/…
  • @FMc,我已经阅读了这两个主题。那里没有我这样的案例。我真的需要基础类并在子类中运行一些方法作为任务芹菜。所以我需要在不改变架构的情况下以某种方式解决我的问题
  • 是的,在这些主题或任何 Celery 文档中都没有像您这样的案例,因为我认为 Celery 不支持针对方法使用任务装饰器。你需要使用一个函数。特别是,在我提供的 * 链接中,请注意 Hamy 的评论。看来您当前的设计根本行不通。
  • @FMc,我已经更新了一些我的问题......我将我的装饰器用作app.task 作为 celery 4.X 提议的文档。这就是为什么我可以肯定它现在支持

标签: python oop celery celery-task


【解决方案1】:

您正在混合使用两种风格的方法:类方法 (@classmethod) 和实例方法 (def calculate_price(self):)。

我还没有真正在代码中尝试过,但是呢:

class Auto(object):
    _year = None
    _base_price = None

    @classmethod
    def calculate_price(cls):
        return cls._base_price + 5000 * (2016 - cls._year)

class BMW(Auto):
    _year = 2015
    _base_price = 40000

    @celery.task(filter=task_method, name='queue_name', base=basetask(), bind=True)
    @classmethod
    def calculate_price(cls, task_self):
        super(BMW, cls).calculate_price()

所以@classmethod装饰器首先应用于def calculate_price(...):,然后@celery.task应用于类方法。

如果您确实需要 calculate_price() 作为实例方法,则签名可以是 def calculate_price(self, task_self): 但您需要在已有实例时应用装饰器,例如:

my_car = BMW()
celery.task(my_car.calculate_price)

当你使用instance<dot>method 访问一个方法时,你不会得到你写的函数,你会得到一个方法描述符,当被调用时,它会负责填写第一个参数 (self) 留给你填写剩下的论点。在这种情况下,只有 task_self 参数,@celery.task 装饰器会处理那个。

无论如何,我认为您应该退后一步,以更通用的方式重新考虑您的问题,而不是弄清楚如何将类/实例方法与 Celery 联系起来。一般来说,Celery 任务应该只是存在于应用程序内部模块中的函数,它们接受可以使用 JSON 轻松序列化的参数。

【讨论】: