Celery: 在工作人员关闭时撤销/中止任务

创建于 2016-02-24  ·  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()

首先,我撤销了 reserved_requests 列表中的任务,以基本上防止任何等待任务在关闭之前接管。

然后我撤销活动请求,然后在任务中触发 SoftTimeLimitExceeded 异常,以便能够在任务中触发清理行为。 由于我使用的是 acks_late (一次只运行一个任务),我需要从任务中返回或提升以正确确认它,并且下次启动工作程序时不要让它重新启动。

我正在使用可中止的任务,但是当用户想要有意中止任务并且系统需要进行一些复杂/长时间的清理时,对中止行为进行了编码。 这种情况更像是工人正在关闭,在这种情况下,我想让当前任务快速失败。

我认为这是在芹菜中做事的正确方法吗?

在未来的版本中,能够简单地重新定义 Task 类中的行为会很好......例如重载 on_revoke() 或 on_abort() 方法。 也许是一种在撤销时有多种行为的方法,具体取决于某些条件......
只是我的 2 美分,我还没有检查 celery v4.0。

所有3条评论

你不能在关机期间向自己发送远程控制命令,你需要使用 worker internals 撤销任务(请参阅远程控制命令在 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()

首先,我撤销了 reserved_requests 列表中的任务,以基本上防止任何等待任务在关闭之前接管。

然后我撤销活动请求,然后在任务中触发 SoftTimeLimitExceeded 异常,以便能够在任务中触发清理行为。 由于我使用的是 acks_late (一次只运行一个任务),我需要从任务中返回或提升以正确确认它,并且下次启动工作程序时不要让它重新启动。

我正在使用可中止的任务,但是当用户想要有意中止任务并且系统需要进行一些复杂/长时间的清理时,对中止行为进行了编码。 这种情况更像是工人正在关闭,在这种情况下,我想让当前任务快速失败。

我认为这是在芹菜中做事的正确方法吗?

在未来的版本中,能够简单地重新定义 Task 类中的行为会很好......例如重载 on_revoke() 或 on_abort() 方法。 也许是一种在撤销时有多种行为的方法,具体取决于某些条件......
只是我的 2 美分,我还没有检查 celery v4.0。

这事有进一步更新吗?

此页面是否有帮助?
0 / 5 - 0 等级