我正在使用 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。
有没有办法,或者这是一个还不可能的定制?
你不能在关机期间向自己发送远程控制命令,你需要使用 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。
这事有进一步更新吗?
最有用的评论
谢谢 !
我设法在工人关闭时撤销正在运行的任务。 :
首先,我撤销了 reserved_requests 列表中的任务,以基本上防止任何等待任务在关闭之前接管。
然后我撤销活动请求,然后在任务中触发 SoftTimeLimitExceeded 异常,以便能够在任务中触发清理行为。 由于我使用的是 acks_late (一次只运行一个任务),我需要从任务中返回或提升以正确确认它,并且下次启动工作程序时不要让它重新启动。
我正在使用可中止的任务,但是当用户想要有意中止任务并且系统需要进行一些复杂/长时间的清理时,对中止行为进行了编码。 这种情况更像是工人正在关闭,在这种情况下,我想让当前任务快速失败。
我认为这是在芹菜中做事的正确方法吗?
在未来的版本中,能够简单地重新定义 Task 类中的行为会很好......例如重载 on_revoke() 或 on_abort() 方法。 也许是一种在撤销时有多种行为的方法,具体取决于某些条件......
只是我的 2 美分,我还没有检查 celery v4.0。