使用上下文管理器从celery的SoftTimeLimitExceeded中恢复

时间:2018-04-06 08:25:18

标签: python celery

我正在尝试为我的芹菜工作设置最长运行时间。

我目前正在使用上下文管理器从异常中恢复。我最终得到的代码与此代码段非常相似:

from celery.exceptions import SoftTimeLimitExceeded

class Manager:

    def __enter__(self):
        return self

    def __exit__(self, error_type, error, tb):
        if error_type == SoftTimeLimitExceeded:
            logger.info('job killed.')
            # swallow the exception
            return True


@task
def do_foo():
    with Manager():
        run_task1()
        run_task2()
        run_task3()

我的期望:

如果do_foo超时run_task1,则记录器会记录,吞下SoftTimeLimitExceeded异常,跳过管理器的主体,作业结束而不运行run_task2和{{1 }}

我观察到的内容: run_task3超时do_foo,引发SoftTimeLimitExceeded,记录器记录,吞下SoftTimeLimitExceeded异常 run_task1run_task2正在运行。

我正在寻找以下两个问题的答案:

  1. 为什么run_task3在此设置中run_task2中引发SoftTimeLimitExceeded后仍然执行?

  2. 是否有一种简单的方法可以转换我的代码,使其能够按预期执行?

1 个答案:

答案 0 :(得分:1)

清理代码

这段代码非常好;没有太多的清理工作。

  • 如果上下文管理器未设计为与self关键字一起使用,则您不应该从__enter__返回as
  • 在检查课程时应该使用
  • is,因为他们是单身......
  • 但您应该更喜欢issubclass来正确模拟异常处理。

实施这些变更给出了:

from celery.exceptions import SoftTimeLimitExceeded

class Manager:
    def __enter__(self):
        pass

    def __exit__(self, error_type, error, tb):
        if issubclass(error_type, SoftTimeLimitExceeded):
            logger.info('job killed.')
            # swallow the exception
            return True

@task
def do_foo():
    with Manager():
        run_task1()
        run_task2()
        run_task3()

调试

我为调试创建了一个模拟环境:

class SoftTimeLimitExceeded(Exception):
    pass

class Logger:
    info = print
logger = Logger()
del Logger

def task(f):
    return f

def run_task1():
    print("running task 1")
    raise SoftTimeLimitExceeded

def run_task2():
    print("running task 2")

def run_task_3():
    print("running task 3")

执行此操作然后您的程序会给出:

>>> do_foo()
running task 1
job killed.

这是预期的行为。

假设

我可以想到两种可能性:

  1. 链中的某些东西,可能是run_task1,是异步的。
  2. celery正在做一些奇怪的事情。
  3. 我会使用第二个假设,因为我无法测试前者。

    我之前被上下文管理器,异常和协同程序之间的组合模糊不清的行为所困扰,所以我知道它导致了什么样的问题。这似乎就是其中之一,但在我可以继续下去之前,我必须先查看celery的代码。

    修改:我无法查找celery代码的头部和尾部,并且搜索没有显示引发SoftTimeLimitExceeded的代码,以允许我追溯它。我会将其传递给有celery更有经验的人,看看他们是否可以解决它是如何运作的。