优雅地终止芹菜任务

时间:2018-01-26 22:28:20

标签: python celery

我正在使用Celery来执行非常长的任务(多个小时),并希望能够杀死个别任务。

如果我没有弄错,这是优雅地终止任务的正确方法:

task = long_task.AsyncResult(task_id)
task.revoke(terminate=True)

我的任务如下:

@celery.task(bind=True, throws=(Terminated,))
def long_task(self):
    try:
        ... do all kinds of things ...   
    except Terminated:
        print("Task was terminated")
    except:
        print("Unknown exception!")

我第一次终止任务时会打印出#34;未知异常!"在控制台上,因此引发异常并在任务中捕获,但不知何故不是Terminated异常。我不明白为什么它没有捕获终止的例外。

我导入了Terminated异常,如下所示:

from billiard.exceptions import Terminated

但事情真的很奇怪,每次我终止一个SECOND任务时,控制台都会给我一个ERROR / MainProcess任务处理程序引发的错误:终止(15,)。我认为正在发生的事情是,这次任务不会引发异常,但工人会这样做。

我想我可以在异常处理程序中包装task.revoke(),但是重点是什么 - 为什么task.revoke()会像这样引发异常?

顺便说一下,任何第三个任务都像第一个任务一样,第四个任务就像第二个任务一样,等等。因此它在任务中不一致,但始终不一致'。

有什么建议吗?

使用Celery 4.1.0,Python 3.5.2和Redis 4.0.7。

1 个答案:

答案 0 :(得分:0)

我遇到了同样的问题,但我使用的是 celery v4.4.0 和 python 3.7

我发现尽管错误消息说明了以下内容

Task handler raised error: Terminated(15)
Traceback (most recent call last):
File "[...]/pool.py", line 1728, in _set_terminated
    raise Terminated(-(signum or 0))
billiard.exceptions.Terminated: 15

这显然是 just a log message 并且实际上引发了 SystemExit 异常。需要注意的是 SystemExit 不是从 Exception 继承的,所以你需要专门用 SystemExit 来捕获它

try:
    ...
except SystemExit as e:
   ...

我的完整工作示例如下,它似乎无需在任务定义中指定异常即可工作。

@app.task()
def long_task():
    try:
        ... do the long thing ...
    except SystemExit:
        print("Task was stopped manually")
    except:
        print("Some other error occured during task execution")
        raise