Celery:中止连接错误的任务

时间:2011-10-06 10:31:30

标签: rabbitmq celery

我必须实现一个Task子类,如果代理没有运行,它会正常失败 - 目前我正在使用RabbitMQ。 我可能只是使用try语句来捕获异常:

try:
    Mytask.delay(arg1, arg2)
except socket.error:
    # Send an notice to an admin
    pass

但是我想创建一个可以处理它的Task的子类。 我尝试过这样的事情:

class MyTask(Task):
    ignore_result = True

    def __call__(self, *args, **kwargs):
        try:
            return self.run(*args, **kwargs)
        except socket.error:
            # Send an notice to an admin
            return None

但工作流程显然是错误的。我想我需要以某种方式注入后端子类或失败策略。 你有什么建议吗?

1 个答案:

答案 0 :(得分:2)

我提出了一个可能的解决方案:

import socket
from celery.decorators import task
from celery.task import Task
from celery.backends.base import BaseBackend

UNDELIVERED = 'UNDELIVERED'


class DummyBackend(BaseBackend):
    """
    Dummy queue backend for undelivered messages (due to the broker being down).
    """
    def store_result(self, *args, **kwargs):
        pass

    def get_status(self, *args, **kwargs):
        return UNDELIVERED

    def _dummy(self, *args, **kwargs):
        return None

    wait_for = get_result = get_traceback = _dummy


class SafeTask(Task):
    """
    A task not raising socket errors if the broker is down.
    """
    abstract = True
    on_broker_error = None
    errbackend = DummyBackend

    @classmethod
    def apply_async(cls, *args, **kwargs):
        try:
            return super(SafeTask, cls).apply_async(*args, **kwargs)
        except socket.error, err:
            if cls.on_broker_error is not None:
                cls.on_broker_error(err, cls, *args, **kwargs)
            return cls.app.AsyncResult(None, backend=cls.errbackend(), 
                task_name=cls.name)


def safetask(*args, **kwargs):
    """
    Task factory returning safe tasks handling socket errors.
    When a socket error occurs, the given callable *on_broker_error*
    is called passing the exception object, the class of the task
    and the original args and kwargs.
    """
    if 'base' not in kwargs:

        on_broker_error = kwargs.pop('on_broker_error', SafeTask.on_broker_error)
        errbackend = kwargs.pop('errbackend', SafeTask.errbackend)
        kwargs['base'] = type('SafeTask', (SafeTask,), {
            'on_broker_error': staticmethod(on_broker_error), 
            'errbackend': errbackend,
            'abstract': True,
        })

    return task(*args, **kwargs)

您既可以将SafeTask子类化,也可以使用装饰器@safetask。 如果你能想到改进,请不要犹豫。