我正在尝试为我的芹菜工作设置最长运行时间。
我目前正在使用上下文管理器从异常中恢复。我最终得到的代码与此代码段非常相似:
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_task1
和run_task2
正在运行。
我正在寻找以下两个问题的答案:
为什么run_task3
在此设置中run_task2
中引发SoftTimeLimitExceeded后仍然执行?
是否有一种简单的方法可以转换我的代码,使其能够按预期执行?
答案 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.
这是预期的行为。
我可以想到两种可能性:
run_task1
,是异步的。celery
正在做一些奇怪的事情。我会使用第二个假设,因为我无法测试前者。
我之前被上下文管理器,异常和协同程序之间的组合模糊不清的行为所困扰,所以我知道它导致了什么样的问题。这似乎就是其中之一,但在我可以继续下去之前,我必须先查看celery
的代码。
修改:我无法查找celery
代码的头部和尾部,并且搜索没有显示引发SoftTimeLimitExceeded
的代码,以允许我追溯它。我会将其传递给有celery
更有经验的人,看看他们是否可以解决它是如何运作的。