web-dev-qa-db-fra.com

Réessayer les tâches de céleri avec une fonction exponentielle

Pour une tâche comme celle-ci:

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(

si elle lève une exception et que je veux la réessayer du côté démon, comment peut appliquer un algorithme de retour exponentiel, c'est-à-dire après 2^2, 2^3,2^4 etc secondes?

La nouvelle tentative est-elle également maintenue du côté serveur, de sorte que si le travailleur se fait tuer, le prochain travailleur qui apparaît se chargera de la nouvelle tentative?

62
Quintin Par

Le task.request.retries L'attribut contient le nombre d'essais jusqu'à présent, vous pouvez donc l'utiliser pour implémenter un back-off exponentiel:

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)

Pour éviter un Thundering Herd Problem , vous pouvez envisager d'ajouter une gigue aléatoire à votre interruption exponentielle:

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

À partir de Celery 4.2, vous pouvez configurer vos tâches pour utiliser automatiquement une interruption exponentielle: http://docs.celryproject.org/en/master/userguide/tasks.html#automatic-retry-for-known-exceptions

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

(Cela figurait déjà dans la documentation de Celery 4.1 mais n'était en fait pas publié à l'époque, voir demande de fusion )

22
Rupert Angermeier