如何杀死Celery任务子进程并仍然获得正确的任务状态?

时间:2016-08-05 18:09:36

标签: python task celery

我正在使用带有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(),但这会忽略所有任务状态,然后我甚至都不会注意到任务取得了成功:/

0 个答案:

没有答案