我正在尝试遵循此Celery Based Background Tasks来为一个简单的应用程序创建一个芹菜设置。
在我的 task.py
中from celery import Celery
def make_celery(app):
celery = Celery(app.import_name, backend=app.config['CELERY_RESULT_BACKEND'],
broker=app.config['CELERY_BROKER_URL'])
celery.conf.update(app.config)
TaskBase = celery.Task
class ContextTask(TaskBase):
abstract = True
def __call__(self, *args, **kwargs):
with app.app_context():
return TaskBase.__call__(self, *args, **kwargs)
celery.Task = ContextTask
return celery
此方法在主烧瓶应用程序的app.py
中有效。
from flask import Flask
flask_app = Flask(__name__)
flask_app.config.update(
CELERY_BROKER_URL='redis://localhost:6379',
CELERY_RESULT_BACKEND='redis://localhost:6379'
)
celery = make_celery(flask_app)
@celery.task()
def add_together(a, b):
return a + b
我的用例是我想在其中创建另一个模块
helpers.py
可以定义异步类的集合。分开 基于芹菜的方法,并将其模块化。
我所做的是将task.py
模块称为其他模块helpers.py
,以创建一个类AsyncMail
来处理电子邮件操作后台工作。
from task import make_celery
class AsyncMail(object):
def __init__(self, app):
"""
:param app: An instance of a flask application.
"""
self.celery = make_celery(app)
def send(self, msg):
print(msg)
现在如何访问self.celery
属性作为该类任何方法的装饰器?
@celery.task()
def send(self, msg):
print(msg)
如果不可能的话,还有什么其他替代步骤可以解决这个问题?
答案 0 :(得分:2)
您无法做您想做的事情。在定义类时,没有self
调用,更不用说self.celery
了,因此您不能使用@self.celery
。即使您使用某种时间机器,也可能会创建38个不同的AsyncMail
实例,您想在这里使用哪个self.celery
?
在开始做自己想做的事情之前,确定要想要吗?您实际上是否希望每个AsyncMail
对象都拥有自己的独立Celery?通常每个应用程序只有一个,这就是为什么通常不会出现这种情况。
如果您确实想要,可以在每个对象都有装饰方法之后,为每个实例提供装饰方法。但这将是丑陋的。
def __init__(self, app):
self.celery = make_celery(app)
# We need to get the function off the class, not the bound method off self
send = type(self).send
# Then we decorate it manually—this is all @self.celery.task does
send = self.celery.task(send)
# Then we manually bind it as a method
send = send.__get__(self)
# And now we can store it as an instance attribute, shadowing the class's
self.send = send
或者,如果您希望将它们全部放在一行中:
self.send = self.celery.task(type(self).send).__get__(self)
对于Python 2,“关闭类的函数”实际上是一个未绑定的方法,并且IIRC您必须调用__get__(self, type(self))
才能将其最终转换为绑定方法,但是否则,它们应该都相同