Celery: Revocación/cancelación de tareas en el cierre del trabajador

Creado en 24 feb. 2016  ·  3Comentarios  ·  Fuente: celery/celery

Estoy usando 3.1.20 (intermediario y back-end de Redis) y me gustaría encontrar una forma de anular/revocar las tareas que se están ejecutando actualmente cuando el trabajador se está cerrando.
El punto es marcar las tareas como FALLIDAS si es posible, y no volver a ejecutarlas la próxima vez que el trabajador comience de nuevo.

Estoy ejecutando una tarea a la vez y dado que la tarea tiene un efecto secundario (y no puedo cambiar eso), matar al trabajador sería el comportamiento esperado del usuario cuando algo sale mal, y no quiero que la tarea se vuelva a ejecutar a continuación. vez que inicio el trabajador (comportamiento predeterminado de sighhandler, creo ...)

He intentado http://stackoverflow.com/a/8230470 sin éxito.
Y también probé algunas cosas usando la interfaz de control o el trabajador desde 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()

instalado de esta manera:

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'))

Sin embargo, parece que mi tarea no se puede revocar/abortar (¿quizás debido a que el trabajador no procesa los mensajes de control después de detenerse?) y me estoy quedando sin ideas.

Si quieres ver más, el código viene de: https://github.com/asmodehn/celeros.

¿Hay alguna manera, o es una personalización que aún no es posible?

Feature Request

Comentario más útil

Gracias !
Me las arreglé para revocar las tareas en ejecución en el cierre del trabajador. :

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()

Primero, revoco la tarea en la lista de solicitudes reservadas para evitar básicamente que cualquier tarea en espera se haga cargo justo antes del cierre.

Luego revoco la solicitud activa y luego activo la excepción SoftTimeLimitExceeded en la tarea para poder activar un comportamiento de limpieza en la tarea. Dado que estoy usando acks_late (para ejecutar solo una tarea a la vez), necesito regresar o subir de la tarea para reconocerla correctamente y que no se reinicie la próxima vez que inicie el trabajador.

Estoy usando tareas abortables, pero el comportamiento de abortar está codificado para cuando un usuario quiere abortar una tarea a sabiendas, y el sistema necesita hacer una limpieza compleja/larga. Este caso es más como si el trabajador se estuviera cerrando, y en ese caso quiero hacer que la tarea actual falle rápidamente.

Creo que esta sería una forma adecuada de hacer las cosas en el apio.

En una versión futura, sería bueno poder simplemente redefinir un comportamiento en la clase Task... por ejemplo, sobrecargar un método on_revoke() o on_abort(). Y tal vez una forma de tener múltiples comportamientos al revocar, dependiendo de algunas condiciones...
Solo mis 2 centavos, aún no he comprobado el apio v4.0.

Todos 3 comentarios

No puede enviarse comandos de control remoto a sí mismo durante el apagado, debe revocar las tareas utilizando los elementos internos del trabajador (vea cómo se implementa el comando de control remoto en celery/worker/control.py).

Probablemente también debería asegurarse de que su paso de arranque dependa del Pool, de modo que su método stop() se llame primero durante el apagado:

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

Gracias !
Me las arreglé para revocar las tareas en ejecución en el cierre del trabajador. :

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()

Primero, revoco la tarea en la lista de solicitudes reservadas para evitar básicamente que cualquier tarea en espera se haga cargo justo antes del cierre.

Luego revoco la solicitud activa y luego activo la excepción SoftTimeLimitExceeded en la tarea para poder activar un comportamiento de limpieza en la tarea. Dado que estoy usando acks_late (para ejecutar solo una tarea a la vez), necesito regresar o subir de la tarea para reconocerla correctamente y que no se reinicie la próxima vez que inicie el trabajador.

Estoy usando tareas abortables, pero el comportamiento de abortar está codificado para cuando un usuario quiere abortar una tarea a sabiendas, y el sistema necesita hacer una limpieza compleja/larga. Este caso es más como si el trabajador se estuviera cerrando, y en ese caso quiero hacer que la tarea actual falle rápidamente.

Creo que esta sería una forma adecuada de hacer las cosas en el apio.

En una versión futura, sería bueno poder simplemente redefinir un comportamiento en la clase Task... por ejemplo, sobrecargar un método on_revoke() o on_abort(). Y tal vez una forma de tener múltiples comportamientos al revocar, dependiendo de algunas condiciones...
Solo mis 2 centavos, aún no he comprobado el apio v4.0.

¿Algún avance en esto?

¿Fue útil esta página
0 / 5 - 0 calificaciones