Celery: Révoquer/abandonner des tâches lors de l'arrêt d'un travailleur

Créé le 24 févr. 2016  ·  3Commentaires  ·  Source: celery/celery

J'utilise 3.1.20 (courtier et backend Redis) et je voudrais un moyen d'abandonner/révoquer les tâches en cours d'exécution lorsque le travailleur est en cours d'arrêt.
Le but est de marquer les tâches comme ÉCHEC si possible, et de ne pas les réexécuter la prochaine fois que le travailleur recommence.

J'exécute une tâche à la fois et comme la tâche a un effet secondaire (et je ne peux pas changer cela), tuer le travailleur serait le comportement attendu de l'utilisateur en cas de problème, et je ne veux pas que la tâche soit réexécutée ensuite heure à laquelle je démarre le travailleur (comportement par défaut du gestionnaire de soupirs, je crois ...)

J'ai essayé http://stackoverflow.com/a/8230470 sans succès.
Et j'ai aussi essayé quelques trucs en utilisant l'interface de contrôle ou le worker depuis un bootstep :

from celery import Celery, bootsteps
from celery.task.control import revoke

# TODO : configuration for tests...
class BootPyrosNode(bootsteps.StartStopStep):

    def __init__(self, worker, **kwargs):
        logging.warn('{0!r} is starting from {1}'.format(worker, __file__))

        [...]

    def create(self, worker):
        return self

    def start(self, worker):
        # our step is started together with all other Worker/Consumer
        # bootsteps.
        pass  # not sure in which process this is run.

    def stop(self, worker):
        # the Consumer calls stop every time the consumer is restarted
        # (i.e. connection is lost) and also at shutdown.  The Worker
        # will call stop at shutdown only.
        logging.warn('{0!r} is stopping. Attempting abort of current tasks...'.format(worker))
        for req in worker.state.active_requests:
            # worker.app.control.revoke(req.id, terminate=True) # not working
            # revoke(req.id, terminate=True) # not working
        self.node_proc.shutdown()

installé de cette façon :

celeros_app = Celery()

# setting up custom bootstep to start ROS node and pass ROS arguments to it
celeros_app.steps['worker'].add(BootPyrosNode)
celeros_app.user_options['worker'].add(Option('-R', '--ros-arg', action="append", help='Arguments for ros initialisation'))

Cependant, il semble que ma tâche ne puisse pas être révoquée/abandonnée (peut-être parce que le travailleur ne traite pas les messages de contrôle après l'arrêt ?) et je suis à court d'idées.

Si vous voulez en voir plus, le code vient de : https://github.com/asmodehn/celeros.

Existe-t-il un moyen, ou est-ce une personnalisation qui n'est pas encore possible ?

Feature Request

Commentaire le plus utile

Merci !
J'ai réussi à révoquer les tâches en cours d'exécution lors de l'arrêt du travailleur. :

def stop(self, worker):
        # the Consumer calls stop every time the consumer is restarted
        # (i.e. connection is lost) and also at shutdown.  The Worker
        # will call stop at shutdown only.
        logging.warn('{0!r} is stopping. Attempting termination of current tasks...'.format(worker))

        # Following code from worker.control.revoke

        task_ids = []
        terminated = set()

        # cleaning all reserved tasks since we are shutting down
        signum = _signals.signum('TERM')
        for request in [r for r in worker.state.reserved_requests]:
            if request.id not in terminated:
                task_ids.append(request.id)
                terminated.add(request.id)
                logger.info('Terminating %s (%s)', request.id, signum)
                request.terminate(worker.pool, signal=signum)

        # Aborting currently running tasks, and triggering soft timeout exception to allow task to clean up.
        signum = _signals.signum('USR1')
        for request in [r for r in worker.state.active_requests]:
            if request.id not in terminated:
                task_ids.append(request.id)
                terminated.add(request.id)
                logger.info('Terminating %s (%s)', request.id, signum)
                request.terminate(worker.pool, signal=signum)  # triggering SoftTimeoutException in Task

        if terminated:
            terminatedstr = ', '.join(task_ids)
            logger.info('Tasks flagged as revoked: %s', terminatedstr)

        self.node_proc.shutdown()

Tout d'abord, je révoque la tâche dans la liste reserves_requests pour empêcher toute tâche en attente de prendre le relais juste avant l'arrêt.

Ensuite, je révoque la demande active, puis je déclenche l'exception SoftTimeLimitExceeded dans la tâche pour pouvoir déclencher un comportement de nettoyage dans la tâche. Étant donné que j'utilise acks_late (pour exécuter une seule tâche à la fois), je dois revenir ou augmenter de la tâche pour la reconnaître correctement et ne pas la faire redémarrer la prochaine fois que je lancerai le travailleur.

J'utilise des tâches avortables, mais le comportement d'abandon est codé lorsqu'un utilisateur souhaite abandonner sciemment une tâche et que le système doit effectuer un nettoyage complexe/long. Ce cas ressemble plus au travailleur qui s'arrête, et dans ce cas, je veux faire échouer rapidement la tâche en cours.

Je pense que ce serait une bonne façon de faire les choses dans le céleri ?

Dans une future version, il serait bien de pouvoir simplement redéfinir un comportement dans la classe Task... par exemple surcharger une méthode on_revoke() ou on_abort(). Et peut-être un moyen d'avoir plusieurs comportements lors de la révocation, selon certaines conditions...
Juste mes 2 cents, je n'ai pas encore vérifié le céleri v4.0.

Tous les 3 commentaires

Vous ne pouvez pas vous envoyer de commandes de contrôle à distance pendant l'arrêt, vous devez révoquer les tâches à l'aide des éléments internes du travailleur (voir comment la commande de contrôle à distance est implémentée dans celery/worker/control.py).

Vous devriez probablement aussi vous assurer que votre bootstep dépend du Pool, afin que votre méthode stop() soit appelée en premier lors de l'arrêt :

class Step..:
    requires = ('celery.worker.components:Pool',)

Merci !
J'ai réussi à révoquer les tâches en cours d'exécution lors de l'arrêt du travailleur. :

def stop(self, worker):
        # the Consumer calls stop every time the consumer is restarted
        # (i.e. connection is lost) and also at shutdown.  The Worker
        # will call stop at shutdown only.
        logging.warn('{0!r} is stopping. Attempting termination of current tasks...'.format(worker))

        # Following code from worker.control.revoke

        task_ids = []
        terminated = set()

        # cleaning all reserved tasks since we are shutting down
        signum = _signals.signum('TERM')
        for request in [r for r in worker.state.reserved_requests]:
            if request.id not in terminated:
                task_ids.append(request.id)
                terminated.add(request.id)
                logger.info('Terminating %s (%s)', request.id, signum)
                request.terminate(worker.pool, signal=signum)

        # Aborting currently running tasks, and triggering soft timeout exception to allow task to clean up.
        signum = _signals.signum('USR1')
        for request in [r for r in worker.state.active_requests]:
            if request.id not in terminated:
                task_ids.append(request.id)
                terminated.add(request.id)
                logger.info('Terminating %s (%s)', request.id, signum)
                request.terminate(worker.pool, signal=signum)  # triggering SoftTimeoutException in Task

        if terminated:
            terminatedstr = ', '.join(task_ids)
            logger.info('Tasks flagged as revoked: %s', terminatedstr)

        self.node_proc.shutdown()

Tout d'abord, je révoque la tâche dans la liste reserves_requests pour empêcher toute tâche en attente de prendre le relais juste avant l'arrêt.

Ensuite, je révoque la demande active, puis je déclenche l'exception SoftTimeLimitExceeded dans la tâche pour pouvoir déclencher un comportement de nettoyage dans la tâche. Étant donné que j'utilise acks_late (pour exécuter une seule tâche à la fois), je dois revenir ou augmenter de la tâche pour la reconnaître correctement et ne pas la faire redémarrer la prochaine fois que je lancerai le travailleur.

J'utilise des tâches avortables, mais le comportement d'abandon est codé lorsqu'un utilisateur souhaite abandonner sciemment une tâche et que le système doit effectuer un nettoyage complexe/long. Ce cas ressemble plus au travailleur qui s'arrête, et dans ce cas, je veux faire échouer rapidement la tâche en cours.

Je pense que ce serait une bonne façon de faire les choses dans le céleri ?

Dans une future version, il serait bien de pouvoir simplement redéfinir un comportement dans la classe Task... par exemple surcharger une méthode on_revoke() ou on_abort(). Et peut-être un moyen d'avoir plusieurs comportements lors de la révocation, selon certaines conditions...
Juste mes 2 cents, je n'ai pas encore vérifié le céleri v4.0.

Une mise à jour pour ceci?

Cette page vous a été utile?
0 / 5 - 0 notes