为什么Celery不会在底层任务抛出异常时抛出异常

时间:2013-02-04 20:12:32

标签: python exception-handling celery

Celery似乎没有正确处理异常。

如果我有任务:

def errorTest():
    raise Exception()

然后我打电话

r = errorTest.delay()
In [8]: r.result

In [9]: r.state
Out[9]: 'PENDING'

它会无限期地挂起来。

去检查日志显示错误被抛出任务(如果你想要消息,请问),我知道后端和一切都设置正确,因为其他任务正常工作并正确返回结果。

在Celery中捕获异常需要做些什么时髦吗?

/ Celery版本是3.0.13,经纪人是在我的本地机器上运行的RabbitMQ

4 个答案:

答案 0 :(得分:29)

如果您在CELERY_ALWAYS_EAGER设置为True的情况下运行Celery,请确保在您的设置中也包含此行:

CELERY_EAGER_PROPAGATES_EXCEPTIONS = True

http://docs.celeryproject.org/en/latest/configuration.html#celery-eager-propagates-exceptions

答案 1 :(得分:13)

您可以在Task子类中定义on_failure函数来正确处理它们。如果您只是想知道发生了什么,可以设置error email notifications,它会在您的芹菜配置中向您发送堆栈跟踪。

注意:截至v4 Celery no longer supports sending emails

答案 2 :(得分:3)

让@ primalpython的答案更明确。

这将失败:

@task
def error():
    raise Exception

输入/输出:

In [7]: r = error.delay()

In [8]: print r.state
Out[8]: 'PENDING'

In [9]: print r.result
Out[9]: None

这将成功:

@task
def error():
    raise Exception

    def on_failure(self, *args, **kwargs):
        pass

输入/输出:

In [7]: r = error.delay()

In [8]: print r.state
Out[8]: 'FAILURE'

In [9]: print r.result
Out[9]: Exception()

答案 3 :(得分:1)

IMO最简单的方法是传入对创建新Celery应用程序时要使用的任务类的引用。

在一个模块中,定义默认使用的任务类:

from celery.app.task import Task
import logging

logger=logging.getLogger(__name__)

class LoggingTask(Task):
  def on_failure(self, exc, task_id, args, kwargs, einfo):
      kwargs={}
      if logger.isEnabledFor(logging.DEBUG):
         kwargs['exc_info']=exc
      logger.error('Task % failed to execute', task_id, **kwargs)
      super().on_failure(exc, task_id, args, kwargs, einfo)

定义应用程序时,请引用模块(注意,这是您提供的字符串引用。):

from celery import Celery

app=Celery('my_project_name', task_cls='task_package.module_name:LoggingTask')

从那时起,如果未专门提供任何任务类,则将使用LoggingTask-从而使您可以实现所有个现有任务(使用默认任务),而不必修改每个任务。这也意味着您可以正常使用@shared_task装饰器。