【发布时间】:2019-09-05 23:20:46
【问题描述】:
我正在用 Python 3.7 编写一个 ETL 框架,它使用函数作为带有特殊装饰器的“任务”。这些任务中的大多数都运行一个循环。如果在循环中引发异常,我希望函数通过记录有关失败的数据来处理此异常,并继续循环。
这是我目前所拥有的一个简化示例:
class TaskExecutionError(RuntimeError):
def __init__(self, msg="", context={}):
self.msg = msg
self.context = context
def __str__(self):
return self.msg or "Error executing task."
def task(fn):
@wraps(fn)
def _wrapper(*args, **kwargs):
start_ts = datetime.utcnow()
try:
return fn(*args, **kwargs)
except TaskExecutionError as e:
logger.exception(f"Task execution error will be logged: {e}.")
fail_data = {
"task_name": fn.__name__,
"args": list(args),
"kwargs": kwargs,
"context": e.context,
"fail_message": str(e),
"fail_time": str(datetime.utcnow()),
# etc.
}
)
# Write failure data in an object store
finally:
end_ts = datetime.utcnow()
logger.info(f"*** Wallclock: {end_ts - start_ts}.")
_wrapper.is_task = True
return _wrapper
@task
def test_fail_log(a, b, c, kwa=1, kwb=2):
"""
Test handling failures.
"""
for i in range(10):
if i % 3:
raise TaskExecutionError(context={"i": i})
else:
print("All's well")
就我看到正在打印和保存的消息而言,这很好用,但是当然,一旦引发第一个异常,执行就会中断。
我应该如何解决这个问题以便继续执行?
似乎我不能使用非常方便的异常机制,我可能必须设计一个自定义的handle_failure() 函数左右。但是我不确定将函数装饰器的上下文传递给 handle failure() 函数的最佳方法,而我从装饰函数中调用它。
由于我将在几个@task 装饰函数中使用这种机制,因此如果可能的话,我希望有一个轻量级的调用,而不需要很多参数。
感谢您提出的任何建议。
【问题讨论】:
标签: python-3.x exception python-decorators