Celery: Revogar/Abortar tarefas no desligamento do trabalhador

Criado em 24 fev. 2016  ·  3Comentários  ·  Fonte: celery/celery

Estou usando o 3.1.20 (broker e back-end do Redis) e gostaria de uma maneira de Abortar/Revogar as tarefas em execução no momento quando o trabalhador estiver sendo desligado.
O ponto é marcar as tarefas como FALHA, se possível, e não executá-las novamente na próxima vez que o trabalhador iniciar novamente.

Estou executando uma tarefa por vez e, como a tarefa tem efeito colateral (e não posso alterar isso), matar o trabalhador seria o comportamento esperado do usuário quando algo der errado e não quero que a tarefa seja executada novamente hora que eu inicio o trabalhador (comportamento padrão do sighandler eu acredito...)

Eu tentei http://stackoverflow.com/a/8230470 sem sucesso.
E também tentei algumas coisas usando a interface de controle ou o trabalhador de uma etapa de inicialização:

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 desta forma:

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

No entanto, parece que minha tarefa não pode ser revogada/anulada (talvez devido ao trabalhador não processar as mensagens de controle após a interrupção?) e estou ficando sem ideias.

Se você quiser ver mais, o código vem de: https://github.com/asmodehn/celeros.

Existe uma maneira, ou isso é uma personalização que ainda não é possível?

Feature Request

Comentários muito úteis

Obrigado !
Consegui revogar tarefas em execução no desligamento do trabalhador. :

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

Primeiro, revogo a tarefa na lista reserved_requests para basicamente impedir que qualquer tarefa em espera assuma pouco antes do desligamento.

Em seguida, revogo a solicitação ativa e aciono a exceção SoftTimeLimitExceeded na tarefa para poder acionar um comportamento de limpeza na tarefa. Como estou usando o acks_late (para executar apenas uma tarefa por vez), preciso retornar ou aumentar da tarefa para reconhecê-la corretamente e não reiniciá-la na próxima vez que iniciar o trabalhador.

Estou usando tarefas abortáveis, mas o comportamento de abortar é codificado para quando um usuário deseja abortar conscientemente uma tarefa e o sistema precisa fazer alguma limpeza complexa/longa. Este caso é mais parecido com o desligamento do trabalhador e, nesse caso, quero fazer com que a tarefa atual falhe rapidamente.

Eu acho que isso seria uma maneira adequada de fazer as coisas no aipo?

Em uma versão futura seria bom poder simplesmente redefinir um comportamento na classe Task... por exemplo, sobrecarregar um método on_revoke() ou on_abort(). E talvez uma forma de ter vários comportamentos ao revogar, dependendo de algumas condições...
Apenas meus 2 centavos, ainda não verifiquei o aipo v4.0.

Todos 3 comentários

Você não pode enviar comandos de controle remoto para si mesmo durante o desligamento, você precisa revogar as tarefas usando os recursos internos do trabalhador (veja como o comando de controle remoto é implementado em celery/worker/control.py).

Você provavelmente também deve certificar-se de que seu bootstep depende do Pool, para que seu método stop() seja chamado primeiro durante o desligamento:

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

Obrigado !
Consegui revogar tarefas em execução no desligamento do trabalhador. :

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

Primeiro, revogo a tarefa na lista reserved_requests para basicamente impedir que qualquer tarefa em espera assuma pouco antes do desligamento.

Em seguida, revogo a solicitação ativa e aciono a exceção SoftTimeLimitExceeded na tarefa para poder acionar um comportamento de limpeza na tarefa. Como estou usando o acks_late (para executar apenas uma tarefa por vez), preciso retornar ou aumentar da tarefa para reconhecê-la corretamente e não reiniciá-la na próxima vez que iniciar o trabalhador.

Estou usando tarefas abortáveis, mas o comportamento de abortar é codificado para quando um usuário deseja abortar conscientemente uma tarefa e o sistema precisa fazer alguma limpeza complexa/longa. Este caso é mais parecido com o desligamento do trabalhador e, nesse caso, quero fazer com que a tarefa atual falhe rapidamente.

Eu acho que isso seria uma maneira adequada de fazer as coisas no aipo?

Em uma versão futura seria bom poder simplesmente redefinir um comportamento na classe Task... por exemplo, sobrecarregar um método on_revoke() ou on_abort(). E talvez uma forma de ter vários comportamentos ao revogar, dependendo de algumas condições...
Apenas meus 2 centavos, ainda não verifiquei o aipo v4.0.

alguma atualização disso?

Esta página foi útil?
0 / 5 - 0 avaliações