我正在使用带有Redis结果后端和RabbitMQ代理的Celery。我有一个包含在shell脚本中的长时间运行的任务(它反过来调用执行繁重的程序)。我希望能够从“外部”杀死子进程,但仍然使用Celery的默认任务状态。
我的任务如下:
@app.task(bind=True, base=AbortableTask)
def my_task(self, shellscrippt_wrapper_command):
proc = subprocess.Popen("exec " + shellscript_wrapper_command,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
shell=True)
my_task.cancel_future_calls = call_repeatedly(5, check_abort_state, self.request.id, proc)
return proc.wait()
辅助功能:
def check_abort_state(task_id, proc):
result = my_task.AsyncResult(task_id)
print("*** is aborted? {}, pid: {}".format(result.is_aborted(), proc.pid))
if result.is_aborted():
print("*** killing task {}".format(task_id))
proc.kill()
my_task.update_state(task_id=task_id, state='FAILURE')
使用call_repeatedly
我启动一个计时器,每隔五秒检查一次任务的状态。
这是我的问题。如果我从外部中止任务(与my_task.abort()
一样),帮助函数check_abort_state
启动,检测 ABORTED 状态并在长时间运行的任务中杀死子进程。到现在为止还挺好。但是my_task()
函数返回Celery意味着任务成功,因此将状态设置为 SUCCESSFUL 覆盖我自己设置的 FAILURE 状态check_abort_state
。在那之后,我对任务的状态不再做任何事情了。它永远设置为成功。
有没有办法阻止这种情况?我希望能够在长时间运行的任务中杀死子进程,但是保留我自己设置的任务状态。
避免它的一种方法是代替return proc.wait()
执行raise celery.exceptions.Ignore()
,但这会忽略所有任务状态,然后我甚至都不会注意到任务取得了成功:/