def retry(time_unit, multiplier, backoff_coefficient, max_delay, max_attempts, expiration_duration, enable_jitter):
def deco_retry(task_to_try):<EOL><INDENT>@wraps(task_to_try)<EOL>def retry_impl(*args, **kwargs):<EOL><INDENT>total_wait_time = <NUM_LIT:0><EOL>have_tried = <NUM_LIT:0><EOL>retry_errors = []<EOL>while have_tried < max_attempts:<EOL><INDENT>try:<EOL><INDENT>task_to_try(*args, **kwargs)<EOL>return<EOL><DEDENT>except Exception as e:<EOL><INDENT>retry_errors.append(e)<EOL>going_to_sleep_for = min(max_delay, multiplier * (backoff_coefficient ** have_tried))<EOL>if enable_jitter:<EOL><INDENT>going_to_sleep_for = random.random() * going_to_sleep_for<EOL><DEDENT>duration = going_to_sleep_for * time_unit<EOL>if total_wait_time + duration > expiration_duration:<EOL><INDENT>raise RetryTimeoutException(task_to_try.__name__, have_tried, max_attempts, total_wait_time,<EOL>multiplier, backoff_coefficient, enable_jitter, retry_errors)<EOL><DEDENT>runtime_logger.warn('<STR_LIT>'<EOL>.format(task_to_try.__name__, duration, traceback.format_exc()))<EOL>time.sleep(duration)<EOL>total_wait_time += duration<EOL><DEDENT>have_tried += <NUM_LIT:1><EOL><DEDENT>raise RetryTimeoutException(task_to_try.__name__, have_tried, max_attempts, total_wait_time, multiplier,<EOL>backoff_coefficient, enable_jitter, retry_errors)<EOL><DEDENT>return retry_impl<EOL><DEDENT>return deco_retry<EOL>
The retry function will keep retrying `task_to_try` until either:
(1) it returns None, then retry() finishes
(2) `max_attempts` is reached, then retry() raises an exception.
(3) if retrying one more time will cause total wait time to go above: `expiration_duration`, then
retry() raises an exception

Beware that any exception raised by task_to_try won't get surfaced until (2) or (3) is satisfied.

At step n, it sleeps for [0, delay), where delay is defined as the following:
`delay = min(max_delay, multiplier * (backoff_coefficient ** (n - 1))) * time_unit` seconds

Additionally, if you enable jitter, for each retry, the function will instead sleep for:
random.random() * sleep, that is [0, sleep) seconds.

:param time_unit: This field represents a fraction of a second, which is used as a
                 multiplier to compute the amount of time to sleep.
:type time_unit: float

:param multiplier: The initial wait duration for the first retry.
:type multiplier: float

:param backoff_coefficient: the base value for exponential retry.
:type backoff_coefficient: float

:param max_delay: The maximum amount of time to wait per try.
:type max_delay: float

:param max_attempts: This method will retry up to this value.
:type max_attempts: int

:param expiration_duration: the maximum amount of time retry can wait.
:type expiration_duration: float

:param enable_jitter: Setting this to true will add jitter.
:type enable_jitter: bool