【问题标题】:Cancel an already executing task with Celery?用 Celery 取消已经执行的任务?
【发布时间】:2012-02-13 19:01:27
【问题描述】:

我一直在阅读文档并进行搜索,但似乎找不到直接的答案:

你能取消一个已经在执行的任务吗? (因为任务已经开始,需要一段时间,中途需要取消)

我从Celery FAQ的文档中找到了这个

>>> result = add.apply_async(args=[2, 2], countdown=120)
>>> result.revoke()

但我不清楚这是否会取消排队的任务,或者是否会杀死工作人员上正在运行的进程。感谢您提供的任何启发!

【问题讨论】:

    标签: python django celery message-passing


    【解决方案1】:

    revoke 取消任务执行。如果任务被撤销,工作人员会忽略该任务并且不执行它。如果您不使用持久撤销,您的任务可以在工作人员重新启动后执行。

    http://docs.celeryproject.org/en/latest/userguide/workers.html#worker-persistent-revokes

    revoke 有一个终止选项,默认为 False。如果您需要终止正在执行的任务,您需要将 terminate 设置为 True

    >>> from celery.task.control import revoke
    >>> revoke(task_id, terminate=True)
    

    http://docs.celeryproject.org/en/latest/userguide/workers.html#revoke-revoking-tasks

    【讨论】:

    • 这正是我正在寻找的解释,谢谢!
    • 这在分布式环境中有效吗?我的意思是,如果我在多台机器上都有工作人员正在执行任务。 celery 是否跟踪任务在哪台机器上执行?
    • 确实如此。与工作人员的通信是通过代理进行的。
    • result.revoke(terminate=True) 应该和 revoke(task_id, terminate=True) 做同样的事情
    • 此外,根据最近的 Celery 文档,使用终止选项是“管理员的最后手段”。您可能会终止最近在该工作人员上启动的另一项任务。
    【解决方案2】:

    在 Celery 3.1 中,API of revoking tasks 已更改。

    根据Celery FAQ,你应该使用result.revoke:

    >>> result = add.apply_async(args=[2, 2], countdown=120)
    >>> result.revoke()
    

    或者如果您只有任务 ID:

    >>> from proj.celery import app
    >>> app.control.revoke(task_id)
    

    【讨论】:

      【解决方案3】:

      @0x00mh 的回答是正确的,但是最近的 celery docs 说使用 terminate 选项是“管理员的最后手段”,因为您可能会意外终止另一个在与此同时。可能更好的解决方案是将terminate=Truesignal='SIGUSR1' 结合使用(这会导致在任务中引发 SoftTimeLimitExceeded 异常)。

      【讨论】:

      • 这个解决方案对我来说效果很好。当我的任务中出现SoftTimeLimitExceeded 时,我的自定义清理逻辑(通过try/except/finally 实现)被调用。在我看来,这比 AbortableTask 提供的 (docs.celeryproject.org/en/latest/reference/…) 要好得多。对于后者,您需要一个数据库结果后端并且您必须手动反复检查正在进行的任务的状态,以查看它是否已中止。
      • 如何更好,据我了解,如果该进程有任何其他任务,无论如何它都会停止,只是会抛出不同的异常。
      • 如果我使用worker_prefetch_multiplier = 1,因为我只有几个长时间运行的任务,终止应该没问题 - 因为终止不会影响其他任务 - 我是否正确? @spicyramen
      【解决方案4】:

      查看以下任务选项:time_limitsoft_time_limit(或者您可以为工作人员设置)。如果您不仅想控制执行时间,请参阅 apply_async 方法的expires 参数。

      【讨论】:

        【解决方案5】:

        另外,不尽人意,还有另一种方式(abort task)可以停止任务,但是有很多不可靠的地方,更多细节请看: http://docs.celeryproject.org/en/latest/reference/celery.contrib.abortable.html

        【讨论】:

          最近更新 更多