Created
June 4, 2013 15:41
-
-
Save willist/5706924 to your computer and use it in GitHub Desktop.
A retry decorator which swallows exceptions until the retry limit is reached.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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