从失败的任务/ uuid中检索Celery任务库

时间:2019-06-29 17:26:23

标签: celery celery-task

主要问题

我正在测试如何处理某些任务失败,例如处理一个'TimeLimitExceeded'异常,该异常会立即终止该任务并且不'可捕获'(是的...我知道'SoftTimeLimit'的存在,但是它不符合我的需求。

第一种方法

这是我的tasks.py(工作人员使用--time-limit标志运行):

import logging
from celery import Celery
import time


app = Celery('tasks', broker='pyamqp://guest@localhost//')

def my_fail(task, exc, req_id, req_args, req_kwargs, einfo, *ext_args, **kwargs):
    logger.info("args: %r", req_args)
    logger.info("kw: %r", req_kwargs)

@app.task(on_failure=my_fail)
def sum(x, y, delay=0, **kw):
    result = x+y
    if result == 4:
        raise Exception("Some Error")
    time.sleep(delay)                                                               
    return x+y

任务失败时的主要思想是能够根据任务的参数/参数执行某些处理

例如,如果我运行sum.delay(3, 1, foo="bar"),则会引发Exception("Some Error")并记录以下内容:

[2019-06-30 17:21:45,120: INFO/Worker-1] args: (3, 1)
[2019-06-30 17:21:45,121: INFO/Worker-1] kw: {'foo': 'bar'}
[2019-06-30 17:21:45,122: ERROR/MainProcess] Task tasks.sum[9e9de032-1469-44e7-8932-4c490fcee2e3] raised unexpected: Exception('Some Error',)
Traceback (most recent call last):
  File "/home/apernin/.virtualenvs/dr/local/lib/python2.7/site-packages/celery/app/trace.py", line 240, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/home/apernin/.virtualenvs/dr/local/lib/python2.7/site-packages/celery/app/trace.py", line 438, in __protected_call__
    return self.run(*args, **kwargs)
  File "/home/apernin/test/tasks.py", line 89, in sum
    raise Exception("Some Error")
Exception: Some Error

请注意,args / kwargs是由我的on-failure处理程序打印的。

现在,如果我运行sum.delay(3, 2, delay=7),则会触发 TimeLimit

[2019-06-30 17:23:15,244: INFO/MainProcess] Received task: tasks.sum[8c81398b-4378-401d-a674-a3bd3418ccde]
[2019-06-30 17:23:21,070: ERROR/MainProcess] Task tasks.sum[8c81398b-4378-401d-a674-a3bd3418ccde] raised unexpected: TimeLimitExceeded(5.0,)
Traceback (most recent call last):
  File "/home/apernin/.virtualenvs/dr/local/lib/python2.7/site-packages/billiard/pool.py", line 645, in on_hard_timeout
    raise TimeLimitExceeded(job._timeout)
TimeLimitExceeded: TimeLimitExceeded(5.0,)
[2019-06-30 17:23:21,071: ERROR/MainProcess] Hard time limit (5.0s) exceeded for tasks.sum[8c81398b-4378-401d-a674-a3bd3418ccde]
[2019-06-30 17:23:21,629: ERROR/MainProcess] Process 'Worker-1' pid:15472 exited with 'signal 15 (SIGTERM)'

请注意,由于on-failure处理程序未被执行,因此args / kwargs被打印出来。由于芹菜的辛苦时间限制,这在某种程度上是可以预期的。

第二种方法

第二种方法是使用事件监听器。

from celery import Celery


def my_monitor(app):
    state = app.events.State()

    def announce_failed_tasks(event):
        state.event(event)
        # task name is sent only with -received event, and state
        # will keep track of this for us.
        task = state.tasks.get(event['uuid'])

    with app.connection() as connection:
        recv = app.events.Receiver(connection, handlers={
                'task-failed': announce_failed_tasks,
        })
        recv.capture(limit=None, timeout=None, wakeup=True)

if __name__ == '__main__':
    app = Celery(broker='amqp://guest@localhost//')
    my_monitor(app)

我能够检索的唯一信息是任务 uuid ,我无法检索任务的名称,args或kwargs(任务对象包含属性,但全都不是。 )。

问题

有没有办法做到这一点?

  • 在硬限时使用on_failure处理程序吗?
  • 使用task-failed事件监听器检索任务的任务args / kwargs?

预先感谢

1 个答案:

答案 0 :(得分:0)

首先,超时是由Worker(MainProcess)处理的,它与任务内部发生的故障(例如引发异常等)的处理方式不同。这就是为什么您将其视为MainProcess引发的TimeLimitExceededed在日志中。因此,很遗憾,您不能依赖相同的逻辑...

但是,您的第二种方法将对跟踪正在发生的事情非常有用。

我已经开发(内部)了一个Celery监视工具,该工具可以捕获所有事件,并用它们填充数据库,以便以后我们可以进行各种分析(例如,请参见平均和最差运行时间,例如失败等)。

为了从task-failed事件提供的数据中获取所需的详细信息,您还需要记录task-received事件数据(例如将其存储在某个字典中)。该信息包含参数,任务名称以及您可能需要的各种有用信息。您可以通过任务UUID将它们关联起来。