Celery: Отзыв/отмена задач при завершении рабочего процесса

Созданный на 24 февр. 2016  ·  3Комментарии  ·  Источник: celery/celery

Я использую 3.1.20 (брокер и бэкэнд Redis), и мне нужен способ прервать/отменить текущие запущенные задачи, когда рабочий выключается.
Смысл в том, чтобы по возможности пометить задачи как FAILED и не запускать их повторно в следующий раз, когда рабочий запустится снова.

Я запускаю одну задачу за раз, и, поскольку задача имеет побочный эффект (и я не могу это изменить), убийство работника будет ожидаемым поведением пользователя, когда что-то пойдет не так, и я не хочу, чтобы задача повторялась в следующий раз. время, когда я запускаю работника (поведение sighandler по умолчанию, я полагаю...)

Я пробовал http://stackoverflow.com/a/8230470 безуспешно.
А еще я пробовал кое-что, используя интерфейс управления или воркер из бутстепа:

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

установил так:

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

Однако кажется, что моя задача не может быть отозвана/прервана (возможно, из-за того, что рабочий не обрабатывает управляющие сообщения после остановки?), и у меня заканчиваются идеи.

Если вы хотите увидеть больше, код взят с: https://github.com/asmodehn/celeros.

Есть ли способ, или это настройка, которая пока невозможна?

Feature Request

Самый полезный комментарий

Спасибо !
Мне удалось отозвать запущенные задачи при завершении рабочего процесса. :

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

Сначала я отменяю задачу в списке зарезервированных_запросов, чтобы предотвратить выполнение любой ожидающей задачи непосредственно перед завершением работы.

Затем я отменяю активный запрос, а затем запускаю исключение SoftTimeLimitExceeded в задаче, чтобы иметь возможность инициировать поведение очистки в задаче. Поскольку я использую acks_late (для запуска только одной задачи за раз), мне нужно вернуться или подняться из задачи, чтобы правильно подтвердить ее и не перезапускать в следующий раз, когда я запускаю работника.

Я использую прерываемые задачи, но поведение прерывания закодировано для случаев, когда пользователь хочет сознательно прервать задачу, а системе необходимо выполнить сложную/долгую очистку. Этот случай больше похож на завершение рабочего процесса, и в этом случае я хочу, чтобы текущая задача быстро завершилась сбоем.

Я думаю, что это был бы правильный способ делать что-то в сельдерее?

В будущей версии было бы неплохо иметь возможность просто переопределить поведение в классе Task... например, перегрузить метод on_revoke() или on_abort(). И, возможно, способ иметь несколько вариантов поведения при отзыве, в зависимости от некоторых условий...
Просто мои 2 цента, я еще не проверял celery v4.0.

Все 3 Комментарий

Вы не можете отправлять команды удаленного управления себе во время выключения, вам нужно отозвать задачи, используя внутренние компоненты worker (см. Как реализована команда удаленного управления в celery/worker/control.py).

Вероятно, вам также следует убедиться, что ваш загрузочный шаг зависит от пула, чтобы ваш метод stop() вызывался первым во время завершения работы:

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

Спасибо !
Мне удалось отозвать запущенные задачи при завершении рабочего процесса. :

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

Сначала я отменяю задачу в списке зарезервированных_запросов, чтобы предотвратить выполнение любой ожидающей задачи непосредственно перед завершением работы.

Затем я отменяю активный запрос, а затем запускаю исключение SoftTimeLimitExceeded в задаче, чтобы иметь возможность инициировать поведение очистки в задаче. Поскольку я использую acks_late (для запуска только одной задачи за раз), мне нужно вернуться или подняться из задачи, чтобы правильно подтвердить ее и не перезапускать в следующий раз, когда я запускаю работника.

Я использую прерываемые задачи, но поведение прерывания закодировано для случаев, когда пользователь хочет сознательно прервать задачу, а системе необходимо выполнить сложную/долгую очистку. Этот случай больше похож на завершение рабочего процесса, и в этом случае я хочу, чтобы текущая задача быстро завершилась сбоем.

Я думаю, что это был бы правильный способ делать что-то в сельдерее?

В будущей версии было бы неплохо иметь возможность просто переопределить поведение в классе Task... например, перегрузить метод on_revoke() или on_abort(). И, возможно, способ иметь несколько вариантов поведения при отзыве, в зависимости от некоторых условий...
Просто мои 2 цента, я еще не проверял celery v4.0.

какие-либо обновления по этому поводу?

Была ли эта страница полезной?
0 / 5 - 0 рейтинги