Python 使用导入的装饰器包装app.task函数时出现芹菜键错误;仅带导入的错误
鉴于布局:Python 使用导入的装饰器包装app.task函数时出现芹菜键错误;仅带导入的错误,python,celery,celery-task,celeryd,Python,Celery,Celery Task,Celeryd,鉴于布局: background \ tasks \ __init__.py generic.py helpers.py __init__.py _server.py config.py router.py server.py 并以芹菜为背景启动\u server.py。\u server worker 当我试图用延迟(…)调用通用.adder函数时,在Worker中给了我一个键错误:u'gene
background \
tasks \
__init__.py
generic.py
helpers.py
__init__.py
_server.py
config.py
router.py
server.py
并以芹菜为背景启动\u server.py
。\u server worker
当我试图用延迟(…)
调用通用.adder
函数时,在Worker中给了我一个键错误:u'generic.adder'
加法器功能:
文件generic.py
from background.server import app
from background.tasks.helpers import standardized_task
@standardized_task(app, name='generic.adder')
def adder(x, y):
return x + y
__author__ = 'Blake'
import types
JSON_TYPES = [
dict, list, unicode, str, int, long, float, bool, types.NoneType
]
def standardized_task(app, *args, **kwargs):
def wrapped_task(fn):
def wrapped_fn(*fnargs, **fnkwargs):
throws = fnkwargs.get('throws', Exception)
raises = fnkwargs.get('raises', False)
if not hasattr(throws, '__call__') and not isinstance(throws(), Exception):
raise ValueError('throws value not of type Exception: %s' % type(throws))
result, error = None, None
try:
result = fn(*fnargs, **fnkwargs)
if type(result) not in JSON_TYPES:
result = unicode(result)
except throws, e:
error = e
if raises:
raise
finally:
return {
'result': result,
'error': str(error) if error else None,
'meta': {
'args': fnargs, 'kwargs': fnkwargs
}
}
return app.task(wrapped_fn, *args, **kwargs)
return wrapped_task
from background.server import app
from background.tasks.generic import *
…用一个函数包装,该函数接受app
实例,并将芹菜任务的输入/输出标准化为JSON对象,该对象返回结果和函数。(包括在下面)然而,当这个包装器函数与generic.adder在同一个文件中时,问题是,它可以完美地工作——当它像上面那样导入和使用时,它抛出关键错误
我相信包装器以某种方式修改了传递给app.task
的name=..
属性,该属性使用helpers.py
中的函数名,这导致从任务访问时找不到generic.adder
的字面名称
还需要注意的是,如果您尝试从\u server.py内部调用加法器(..)
(该模块从芹菜CLI运行),那么它的工作原理是完美的;只有通过分布式接口调用时才会抛出错误;也就是说,进口产品独立于芹菜
文件helpers.py
from background.server import app
from background.tasks.helpers import standardized_task
@standardized_task(app, name='generic.adder')
def adder(x, y):
return x + y
__author__ = 'Blake'
import types
JSON_TYPES = [
dict, list, unicode, str, int, long, float, bool, types.NoneType
]
def standardized_task(app, *args, **kwargs):
def wrapped_task(fn):
def wrapped_fn(*fnargs, **fnkwargs):
throws = fnkwargs.get('throws', Exception)
raises = fnkwargs.get('raises', False)
if not hasattr(throws, '__call__') and not isinstance(throws(), Exception):
raise ValueError('throws value not of type Exception: %s' % type(throws))
result, error = None, None
try:
result = fn(*fnargs, **fnkwargs)
if type(result) not in JSON_TYPES:
result = unicode(result)
except throws, e:
error = e
if raises:
raise
finally:
return {
'result': result,
'error': str(error) if error else None,
'meta': {
'args': fnargs, 'kwargs': fnkwargs
}
}
return app.task(wrapped_fn, *args, **kwargs)
return wrapped_task
from background.server import app
from background.tasks.generic import *
文件\u server.py
from background.server import app
from background.tasks.helpers import standardized_task
@standardized_task(app, name='generic.adder')
def adder(x, y):
return x + y
__author__ = 'Blake'
import types
JSON_TYPES = [
dict, list, unicode, str, int, long, float, bool, types.NoneType
]
def standardized_task(app, *args, **kwargs):
def wrapped_task(fn):
def wrapped_fn(*fnargs, **fnkwargs):
throws = fnkwargs.get('throws', Exception)
raises = fnkwargs.get('raises', False)
if not hasattr(throws, '__call__') and not isinstance(throws(), Exception):
raise ValueError('throws value not of type Exception: %s' % type(throws))
result, error = None, None
try:
result = fn(*fnargs, **fnkwargs)
if type(result) not in JSON_TYPES:
result = unicode(result)
except throws, e:
error = e
if raises:
raise
finally:
return {
'result': result,
'error': str(error) if error else None,
'meta': {
'args': fnargs, 'kwargs': fnkwargs
}
}
return app.task(wrapped_fn, *args, **kwargs)
return wrapped_task
from background.server import app
from background.tasks.generic import *
答案不是使用装饰器,而是将芹菜.Task扩展到一个抽象类中,并使用,@app.Task(name='…',base=MyNewAbstractTask)
下面的帖子对此进行了更好的解释: