重试芹菜任务并以指数方式退回


73

对于这样的任务:

from celery.decorators import task

@task()
def add(x, y):
    if not x or not y:
        raise Exception("test error")
    return self.wait_until_server_responds(

如果它引发异常,而我想从守护程序端重试,如何应用指数退避算法,即 2^2, 2^3,2^4等数秒后?

还从服务器端维护重试,以便如果该工作程序正好被杀死,那么产生的下一个工作程序将执行重试任务?

Answers:


133

task.request.retries属性包含到目前为止的尝试次数,因此您可以使用它来实现指数补偿:

from celery.task import task

@task(bind=True, max_retries=3)
def update_status(self, auth, status):
    try:
        Twitter(auth).update_status(status)
    except Twitter.WhaleFail as exc:
        self.retry(exc=exc, countdown=2 ** self.request.retries)

为防止雷电群问题,您可以考虑将随机抖动添加到指数补偿中:

import random
self.retry(exc=exc, countdown=int(random.uniform(2, 4) ** self.request.retries))

您知道这是服务器端重试还是让客户端等待?如果客户不得不等待,那就不好了。
昆丁票面值2012年

2
据我所知,倒数属性为MQ后端(例如RabbitMQ)的任务设置了一个eta。因此,它不是在客户端设置的。
idanzalz 2012年

除非您result.get()明确要求客户等待结果准备就绪,否则客户端不会一直等待,但是还有一个超时参数和一个RETRY状态,因此您可以检查任务是否被重试(原因是什么)重试是)
asksol 2012年

9
对于celery 3.1,您应该使用@task(bind=True)celery并将self其作为第一个参数传递给函数,因此您将args更改为def update_status(self, auth, status):,然后您就可以访问self.retries
robbyt 2013年

2
谢谢@robbyt!只是一个小的更正-retries是的属性requestself.request.retries正确的调用也是如此。
tutuDajuju 2015年

36

从Celery 4.2开始,您可以将任务配置为自动使用指数补偿:http : //docs.celeryproject.org/en/master/userguide/tasks.html#automatic-retry-for-known-exceptions

@app.task(autoretry_for=(Exception,), retry_backoff=2)
def add(x, y):
    ...

(这已经存在于Celery 4.1的文档中,但实际上当时并未发布,请参阅合并请求


3
不错的收获,在4.1.0中犹豫不决,为什么我的参数“ retry_backoff”不被尊重。
kororo

2
@kororo它似乎不起作用self.retry,只有其他异常类型
rdrey

使用这种方法,您还可以从内置的retry_jitter(默认为True)中受益,它避免了Asksol的答案中提到的“雷电群问题”
qwertysmack
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.