В своих последних проектах я начал часто использовать декораторы для обработки ошибок. Удобно, что эту логику можно вынести в отдельное место и она не будет засорять основную логику. Плюс не надо такие обработчики писать каждый раз, а можно на самом деле переиспользовать код. Например, функция-декоратор ниже просто записывает ошибку в лог и пробрасывает ее дальше:
def error_logger(decorated):
def decorator(*args, **kwargs):
try:
return decorated(*args, **kwargs)
except:
log.error("error in %s:", decorated.__name__, exc_info=True)
raise
return decorator
Один из моих последних декораторов - это декоратор для асинхронных функций обращения к базе данных с использованием Twsited. Он позволяет в случае временной ошибки попытаться повторить запрос еще несколько раз:
def retry_on_error(decorated):
retry_timeout = 10
retry_count = 3
def error_handler(failure, retry_count, args, kwargs):
retry_count -= 1
if (retry_count >= 0
and failure.check(adbapi.ConnectionLost, dberror.InterfaceError,
dberror.OperationalError, dberror.InternalError)):
log.warning(
"error %s in %s, retry in %s seconds, %s retries remained",
format_failure(failure), decorated.__name__,
retry_timeout, retry_count)
deferred = defer.Deferred()
reactor.callLater(retry_timeout, deferred.callback, None)
return deferred.addCallback(retry, retry_count, args, kwargs)
return failure
def retry(ignored, retry_count, args, kwargs):
deferred = decorated(*args, **kwargs)
return deferred.addErrback(error_handler, retry_count, args, kwargs)
def decorator(*args, **kwargs):
deferred = decorated(*args, **kwargs)
return deferred.addErrback(error_handler, retry_count, args, kwargs)
return decorator
Add comment