В своих последних проектах я начал часто использовать декораторы для обработки ошибок. Удобно, что эту логику можно вынести в отдельное место и она не будет засорять основную логику. Плюс не надо такие обработчики писать каждый раз, а можно на самом деле переиспользовать код. Например, функция-декоратор ниже просто записывает ошибку в лог и пробрасывает ее дальше:
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