def retry(retry_exceptions=RETRY_EXCEPTIONS, retry_delay=DEFAULT_DELAY,
          timeout=DEFAULT_TIMEOUT, backoff=DEFAULT_BACKOFF):
    """
    Retry decorator that helps to handle common transient exceptions.

    :param retry_exceptions: types of exceptions to retry on.
    :param retry_delay: retry delay between the attempts.
    :param timeout: maximum time to wait.
    :param backoff: multiplier added to delay between attempts.

    :Example:

    retry_request = retry(timeout=1, retry_delay=1, backoff=1)
    retry_request(self.connection.request)()
    """
    if retry_exceptions is None:
        retry_exceptions = RETRY_EXCEPTIONS
    if retry_delay is None:
        retry_delay = DEFAULT_DELAY
    if timeout is None:
        timeout = DEFAULT_TIMEOUT
    if backoff is None:
        backoff = DEFAULT_BACKOFF

    timeout = max(timeout, 0)

    def transform_ssl_error(func, *args, **kwargs):
        try:
            return func(*args, **kwargs)
        except ssl.SSLError:
            exc = sys.exc_info()[1]

            if TRANSIENT_SSL_ERROR in str(exc):
                raise TransientSSLError(*exc.args)

            raise exc

    def decorator(func):
        @wraps(func)
        def retry_loop(*args, **kwargs):
            current_delay = retry_delay
            end = datetime.now() + timedelta(seconds=timeout)

            while True:
                try:
                    return transform_ssl_error(func, *args, **kwargs)
                except retry_exceptions:
                    exc = sys.exc_info()[1]

                    if isinstance(exc, RateLimitReachedError):
                        time.sleep(exc.retry_after)

                        # Reset retries if we're told to wait due to rate
                        # limiting
                        current_delay = retry_delay
                        end = datetime.now() + timedelta(
                            seconds=exc.retry_after + timeout)
                    elif datetime.now() >= end:
                        raise
                    else:
                        time.sleep(current_delay)
                        current_delay *= backoff

        return retry_loop
    return decorator
dataset/ETHPy150Open apache/libcloud/libcloud/utils/misc.py/retry/original