Skip to content

Instantly share code, notes, and snippets.

@willist
Created June 4, 2013 15:41
Show Gist options
  • Save willist/5706924 to your computer and use it in GitHub Desktop.
Save willist/5706924 to your computer and use it in GitHub Desktop.
A retry decorator which swallows exceptions until the retry limit is reached.
import time
import math
import logging
retry_logger = logging.getLogger('retry_logger')
# Retry decorator with exponential backoff
def retry(tries, delay=3, backoff=2):
'''Retries a function or method until it completes or the retry limit is reached.
delay sets the initial delay in seconds, and backoff sets the factor by which
the delay should lengthen after each failure. backoff must be greater than 1,
or else it isn't really a backoff. tries must be at least 0, and delay
greater than 0.'''
if backoff <= 1:
raise ValueError("backoff must be greater than 1")
tries = math.floor(tries)
if tries < 0:
raise ValueError("tries must be 0 or greater")
if delay <= 0:
raise ValueError("delay must be greater than 0")
def deco_retry(f):
def f_retry(*args, **kwargs):
mtries, mdelay = tries, delay # make mutable
while mtries > 0:
try:
logging.info('Making attempt')
rv = f(*args, **kwargs)
return rv
except Exception:
logging.info('Attempt failed')
mtries -= 1 # consume an attempt
logging.info('Delay of {0} seconds'.format(mdelay))
time.sleep(mdelay) # wait...
mdelay *= backoff # make future wait longer
if not mtries:
logging.info('Out of retries.')
raise
return None # Should never get here
return f_retry
return deco_retry
if __name__ == "__main__":
# paltry testing
logging.basicConfig(level=logging.INFO)
times_to_fail = 5
state_seed = [0] * times_to_fail + [1]
state = (x for x in [0, 0, 0, 0, 0, 1])
@retry(6, delay=1)
def fail_then_succeed():
if next(state):
return 'Success!'
else:
#return 'Failure :('
raise ValueError("Not Yet")
print fail_then_succeed()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment