Skip to content

Instantly share code, notes, and snippets.

@rmg
Created February 24, 2010 22:32
Show Gist options
  • Save rmg/313956 to your computer and use it in GitHub Desktop.
Save rmg/313956 to your computer and use it in GitHub Desktop.
Little retry loop wrappers (handling return codes and exceptions)
from functools import wraps
def retry(attempts, f):
"""
Returns a callable that will invoke @f() and return result, suppressing
exceptions up to @attempts times
"""
@wraps(f)
def wrapper(*args, **kwds):
hardfail = None
for i in range(attempts):
try:
return f(*args, **kwds)
except Exception as e:
hardfail = e
if __debug__:
print("Failed to execute {0} -> {1}\n".format(f, e))
time.sleep(i)
raise hardfail
return wrapper
def retry_until(attempts, f, until):
"""
Retruns a callable that will call @f() until @until is returned or
@attempts has been exceeded.
"""
@wraps(f)
def wrapper(*args, **kwds):
hardfail = None
for i in range(attempts):
try:
# only want to capture the last exception if it was the cause
# of the failure
hardfail = None
if f(*args, **kwds) == until:
return True
except Exception as e:
hardfail = e
if __debug__:
print("Failed to execute {0} -> {1}\n".format(f, e))
time.sleep(i)
if hardfail:
raise hardfail
return False
return wrapper
import os
# The original use case of retry_until was transient erros when unmounting filesystems that may be busy for a couple seconds
retry_until(5, os.system, 0)("umount /tmp/foo")
# Useless example
retry_until(5, os.system, 0)("ls /foobar")
# ls: cannot access foo: No such file or directory
# ls: cannot access foo: No such file or directory
# ls: cannot access foo: No such file or directory
# ls: cannot access foo: No such file or directory
# ls: cannot access foo: No such file or directory
# False
# The original use of retry was for retry_until cases that involve exceptions being thrown
retry(10, shutil.rmtree)("/tmp/foo")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment