Source code for core_mixins.decorators.retry
# -*- coding: utf-8 -*-
"""Retry decorator with exponential backoff for handling exceptions."""
from functools import wraps
from logging import Logger
from time import sleep
from typing import Callable, Type, Tuple, Optional
[docs]
def retry( # pylint: disable=too-many-arguments,too-many-positional-arguments
fcn: Optional[Callable] = None,
tries: int = 3,
delay: int = 1,
backoff: int = 2,
exceptions: Tuple[Type[BaseException], ...] = (Exception,),
logger: Optional[Logger] = None,
) -> Callable:
"""
It retries the decorated function using an exponential
backoff in case of errors (exceptions) in the
execution...
:param fcn: The function being decorated.
:type fcn: Callable
:param tries: Number of retries.
:type tries: int
:param delay: Delay in seconds between invocations.
:type delay: int
:param backoff: Exponential backoff to used between retries.
:type backoff: int
:param exceptions:
Exceptions to capture for the retries. If the raised exception is not
here, no retries are performed.
:type exceptions: Callable
:param logger: The function being decorated.
:type logger: Callable
:return: The wrapped function.
:rtype: Callable
"""
def decorator_retry(_fcn: Callable) -> Callable:
@wraps(_fcn)
def function_retry(*args, **kwargs):
_tries, _delay = tries, delay
while _tries > 1:
try:
return _fcn(*args, **kwargs)
except exceptions as error:
if logger:
logger.warning(f"Retrying in {_delay}. Because: {error}")
sleep(_delay)
_tries -= 1
_delay *= backoff
return _fcn(*args, **kwargs)
return function_retry
if not fcn:
return decorator_retry
return decorator_retry(fcn)