Skip to content

Instantly share code, notes, and snippets.

@MihanixA
Created February 12, 2020 00:01
Show Gist options
  • Save MihanixA/83c6309bfd1e01ccea456c921a60bb0d to your computer and use it in GitHub Desktop.
Save MihanixA/83c6309bfd1e01ccea456c921a60bb0d to your computer and use it in GitHub Desktop.
Python Exponential Retry Decorator
import time
import math
from copy import deepcopy
from typing import List, Type, Union, Callable, Any, Optional
from functools import wraps
def exp_retry(count: int = 5, power: Union[int, float] = 2, ignore_exceptions: List[Type[BaseException]] = None,
raise_on_failure: Optional[Type[BaseException]] = Exception) -> Callable:
ignore_exceptions: list = deepcopy(ignore_exceptions) if ignore_exceptions is not None else list()
def decorator(f: Callable) -> Callable:
retries_so_far: int = 0
@wraps(f)
def wrapper(*args, **kwargs) -> Any:
nonlocal retries_so_far
while retries_so_far < count:
try:
return f(*args, **kwargs)
except Exception as e:
should_ignore = False
for exc in ignore_exceptions:
if isinstance(e, exc):
should_ignore = True
if not should_ignore:
retries_so_far += 1
timeout: float = math.pow(retries_so_far, power)
print(f'\033[93mretrying in {timeout:.2f}s, retries left {count - retries_so_far:,}\033[0m')
time.sleep(timeout)
else:
print(f'\033[91mexception ignored\033[0m')
raise
else:
print('\033[91mretry limit exceeded\033[0m')
if raise_on_failure:
raise raise_on_failure()
return wrapper
return decorator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment