Skip to content

Instantly share code, notes, and snippets.

@danielhfrank
Created May 9, 2013 20:50
Show Gist options
  • Save danielhfrank/5550523 to your computer and use it in GitHub Desktop.
Save danielhfrank/5550523 to your computer and use it in GitHub Desktop.
Attempt at a retry-with-backoff decorator. May it (and I) rest in peace
def retry_with_backoff(method):
"""
The idea was to use this to decorate a method that makes some kind of request and has a callback
kwarg. The callback will be decorated to retry the calling function a few times,
with backoff, if it receives an error.
"""
@functools.wraps(method)
def caller_wrapper(self, *args, **kwargs):
callback = kwargs['callback']
attempts = kwargs.pop('attempts', 0)
@functools.wraps(callback)
def callback_wrapper(*args, **kwargs):
error = test_and_get_error(args[0])
if error and attempts < MAX_ATTEMPTS:
# Try the request again
retry_at = time.time() + INITIAL_DELAY * 2 ** attempts
kwargs['attempts'] = attempts + 1
tornado.ioloop.IOLoop.instance().add_timeout(retry_at,
functools.partial(method, *args, **kwargs))
else:
# Proceed with the callback, in good times or in bad
return callback(*args, **kwargs)
kwargs['callback'] = callback_wrapper
return method(self, *args, **kwargs)
return caller_wrapper
def test_and_get_error(data):
if isinstance(data, tornado.httpclient.HTTPResponse) and data.error:
return data.error
elif isinstance(data, Exception):
return data
return None
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment