在RQ中重试失败的作业

时间:2013-01-17 22:51:31

标签: python web-applications asynchronous wsgi

我们正在使用RQ和我们的WSGI应用程序。我们所做的是在运行任务的不同后端服务器中有几个不同的进程,连接到(可能)几个不同的任务服务器。为了更好地配置此设置,我们在系统中使用自定义管理层,负责运行工作人员,设置任务队列等。

当一个作业失败时,我们希望实现一个重试,它会在一个延迟增加后多次重试一个作业,并最终完成它或让它失败并在我们的日志记录系统中记录一个错误条目。但是,我不确定应该如何实施。我已经创建了一个自定义工作脚本,它允许我们将错误记录到我们的数据库中,我第一次尝试重试就是这样的:

# This handler would ideally wait some time, then requeue the job.
def worker_retry_handler(job, exc_type, exc_value, tb):
    print 'Doing retry handler.'
    current_retry = job.meta[attr.retry] or 2

    if current_retry >= 129600:
        log_error_message('Job catastrophic failure.', ...)
    else:
        current_retry *= 2

        log_retry_notification(current_retry)
        job.meta[attr.retry] = current_retry
        job.save()
        time.sleep(current_retry)

        job.perform()

return False

正如我所提到的,我们在worker文件中也有一个函数可以正确地解析它应该连接的服务器,并且可以发布作业。问题不一定是如何发布作业,而是要做什么与您在异常处理程序中获得的作业实例。

非常感谢任何帮助。如果有更好的方法可以提出建议或指示,这也会很棒。谢谢!

2 个答案:

答案 0 :(得分:1)

我看到两个可能的问题:

  1. 您应该有一个返回值。 False可防止默认异常处理发生在作业中(请参阅本页的最后一节:http://python-rq.org/docs/exceptions/

  2. 我认为当您的处理程序被调用时,作业不再排队。我不是100%肯定(特别是考虑到我在上面指出的文档),但是如果它在失败的队列中,你可以调用requeue_job(job.id)来重试它。如果不是(它听起来不会),你可能会抓住正确的队列并直接排队。

答案 1 :(得分:0)

强文本我有一个更漂亮的解决方案

from rq import Queue, Worker
from redis import Redis

redis_conn = Redis(host=REDIS_HOST, health_check_interval=30)
queues = [
    Queue(queue_name, connection=redis_conn, result_ttl=0) 
    for queue_name in ["Low", "Fast"]
]
worker = Worker(queues, connection=redis, exception_handlers=[retry_handler])


def retry_handler(job, exc_type, exception, traceback):
    if isinstance(exception, RetryException):
        sleep(RetryException.sleep_time)
        job.requeue()
        return False

处理程序本身负责确定是否完成了异常处理,还是应该落入堆栈中的下一个处理程序。处理程序可以通过返回布尔值来表明这一点。 False 表示停止处理异常, True 表示继续并进入堆栈中的下一个异常处理程序。

对于实现者来说,很重要的一点是,默认情况下,当处理程序没有显式的返回值(因此)时,这将被解释为 (即,继续使用下一个处理程序)。

要防止执行处理程序链中的下一个异常处理程序,请使用不存在的自定义异常处理程序,例如: