Skip to content

Instantly share code, notes, and snippets.

@iamFIREcracker
Created October 15, 2017 17:00
Show Gist options
  • Save iamFIREcracker/fecdd30a1ca2bf0e84a7fdec06f3fd79 to your computer and use it in GitHub Desktop.
Save iamFIREcracker/fecdd30a1ca2bf0e84a7fdec06f3fd79 to your computer and use it in GitHub Desktop.
Python decorator to recover from failed function calls
#!/usr/bin/env python
"""Script showing how to use decorators to recover from failed function calls
"""
import sys
import time
def backoff1(step):
def wrapper1(func):
def wrapper2(*args, **kwargs):
delta = step
while not func(*args, **kwargs):
print "Sleeping for {0} seconds".format(delta)
time.sleep(delta)
delta *= 2
return wrapper2
return wrapper1
def backoff2(step, linear):
def wrapper1(func):
def wrapper2(*args, **kwargs):
delta = step
exponential = True
while not func(*args, **kwargs):
print "Sleeping for {0} seconds".format(delta)
time.sleep(delta)
if not exponential:
delta += step
else:
new_delta = delta * 2
if new_delta < linear:
delta = new_delta
else:
delta = linear
exponential = False
return wrapper2
return wrapper1
class ExecutionLimitException(Exception):
"""Exception raised if a backoffed function keep failing and failing."""
def __init__(self, func, *args, **kwargs):
"""
Keywords:
func failed function.
args positional arguments passed to the function.
kwargs named arguments passed to the function.
"""
super(ExecutionLimitException, self).__init__(
"Function: {0} Arguments: {1} {2}".format(
func.func_name, args, kwargs))
self.func = func
self.args_ = args # self.args seems to be used by someonelse...
self.kwargs = kwargs
def backoff3(step, linear, limit):
def wrapper1(func):
def wrapper2(*args, **kwargs):
delta = step
exponential = True
left = limit # prevent UnboundLocalError exception
while not func(*args, **kwargs):
if left is not None:
left -= 1
if not left:
raise ExecutionLimitException(func, *args, **kwargs)
print "Sleeping for {0} seconds".format(delta)
time.sleep(delta)
if not exponential:
delta += step
else:
new_delta = delta * 2
if new_delta < linear:
delta = new_delta
else:
delta = linear
exponential = False
return wrapper2
return wrapper1
def _evalfunc(v):
"""Return True if and only if input argument is True."""
return v == True
def backoff4(step, linear, limit, evalfunc=_evalfunc):
def wrapper1(func):
def wrapper2(*args, **kwargs):
delta = step
exponential = True
left = limit # prevent UnboundLocalError exception
while not evalfunc(func(*args, **kwargs)):
if left is not None:
left -= 1
if not left:
raise ExecutionLimitException(func, *args, **kwargs)
print "Sleeping for {0} seconds".format(delta)
time.sleep(delta)
if not exponential:
delta += step
else:
new_delta = delta * 2
if new_delta < linear:
delta = new_delta
else:
delta = linear
exponential = False
return wrapper2
return wrapper1
def _waitfunc(delta):
"""Sleep for the given period of time, then return."""
import time as _time
_time.sleep(delta)
def backoff5(step, linear, limit, evalfunc=_evalfunc, waitfunc=_waitfunc):
def wrapper1(func):
def wrapper2(*args, **kwargs):
delta = step
exponential = True
left = limit
while not evalfunc(func(*args, **kwargs)):
if left is not None:
left -= 1
if not left:
raise ExecutionLimitException(func, *args, **kwargs)
print "Sleeping for {0} seconds".format(delta)
waitfunc(delta)
if not exponential:
delta += step
else:
new_delta = delta * 2
if new_delta < linear:
delta = new_delta
else:
delta = linear
exponential = False
return wrapper2
return wrapper1
def backoff(step, linear, limit, evalfunc=_evalfunc, waitfunc=_waitfunc):
def wrapper1(func):
def wrapper2(*args, **kwargs):
delta = step
exponential = True
left = limit
while not evalfunc(func(*args, **kwargs)):
if left is not None:
left -= 1
if not left:
raise ExecutionLimitException(func, *args, **kwargs)
waitfunc(delta)
if not exponential:
delta += step
else:
new_delta = delta * 2
if new_delta < linear:
delta = new_delta
else:
delta = linear
exponential = False
return wrapper2
return wrapper1
class DecoratedFunction(object):
def __init__(self, func, dec, *args, **kwargs):
self._func = func
self._dec = dec(*args, **kwargs)
def __call__(self, *args, **kwargs):
self._dec(self._func)(*args, **kwargs)
def noman():
"""Function which always return False."""
return False
def waitnprint(delta):
print "Sleeping for {0} seconds".format(delta)
time.sleep(delta)
def testwait(delta):
print "Sleeping for {0} seconds".format(delta)
def main(args):
def lognsleep(delta):
print "Sleeping for {0} seconds".format(delta)
#time.sleep(delta)
DecoratedFunction(noman, backoff5, step=1, linear=60, limit=10,
waitfunc=lognsleep)()
if __name__ == '__main__':
main(sys.argv)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment