1 """!Contains retry_io() which automates retrying operations."""
11 def retry_io(max_tries,sleep_time,operation,opargs=[],logger=None,
12 fail=
None,failargs=[],giveup=
None,giveupargs=[],randsleep=
True,
13 backoff=1.3,first_warn=0,giveup_quiet=
False):
14 """!This function automates retrying an unreliable operation
15 several times until it succeeds. This subroutine will retry the
16 operation up to a maximum number of times. If the operation fails
17 too many times, then the last exception thrown by the operation is
18 passed on (raised) to the caller.
20 @param max_tries Maximum number of times to attempt the operation (mandatory)
21 @param sleep_time Time to sleep between tries
22 @param operation A function or callable object that may thrown an Exception
23 @param opargs A list containing arguments to the operation
24 @param logger A logging.Logger object to use for logging, or None
26 @param fail A string to print, or a function to call, when
27 the operation fails but more retries are possible
28 @param failargs Optional: a list of arguments to fail, or None to disable
29 @param giveup A string to print, or a function to call when the
30 operation fails too many times, causing retry_io
31 to give up. Default: same as fail
32 @param giveupargs Optional: a list of arguments to giveup, or None to disable
33 @param randsleep Set to True (default) to enable an exponential backoff
34 algorithm, which will increase the sleep time between tries
35 @param backoff The exponent for the exponential backoff algorithm
36 @param first_warn The first failure at which to warn via the logger
37 @param giveup_quiet If True, a WARNING-level message is sent to the logger
38 if the operation fails more than max_tries times.
39 @return The return value of the operation.
40 @note If fail or giveup are functions, they are passed the contents of
41 failargs (default: opargs) or giveupargs (default: failargs or
42 opargs) with several additional arguments appended. Those
43 arguments are the exception that was caught, the number of
44 attempts so far, the max_tries, the sleep_time, and then a boolean
45 that is true iff the operation is about to be retried."""
49 if failargs
is None: failargs=opargs
50 if giveup
is None: giveup=fail
51 if giveup
is not None:
52 if giveupargs
is None: giveupargs=failargs
54 if sleep_time
is None:
58 for ntry
in xrange(max_tries):
60 if logger
is not None:
61 logger.debug(
'%s(%s)'%(repr(operation),repr(opargs)))
62 return operation(*opargs)
63 except(Exception)
as e:
66 if logger
is not None:
67 logger.debug(
'Failed but have not given up: %s'%(str(e),),
69 if sleep_time
is not None:
71 sleepmax=min(sleep_time,0.05) * \
72 min(max(1.0,backoff**ntry),50.0)
73 sleepme=random.uniform(sleepmax/2.0,sleepmax)
74 if isinstance(fail,basestring):
75 if logger
is not None and ntry>=first_warn:
76 logger.info(
"%s (try %d/%d; sleep %.3f and retry): %s"%\
77 (fail,ntry+1,max_tries,sleepme,repr(e)))
78 elif fail
is not None:
80 arglist.extend([e,ntry+1,max_tries,sleep_time,
True])
81 if logger
is not None:
82 logger.debug(
'arglist to fail (1): '+repr(arglist))
84 time.sleep(max(0.05,sleepme))
87 if logger
is not None:
88 logger.debug(
'Failed and gave up: %s'%(str(e),),
90 if isinstance(giveup,basestring)
and not giveup_quiet:
91 if logger
is not None:
92 logger.warning(
"%s (giving up after %d tries): %s"%\
93 (giveup,ntry+1,repr(e)),exc_info=
True)
94 elif giveup
is not None:
96 arglist.extend([e,ntry+1,max_tries,sleep_time,
False])
97 if logger
is not None:
98 logger.debug(
'arglist to fail (2): '+repr(arglist))
99 if isinstance(fail,basestring):
def retry_io
This function automates retrying an unreliable operation several times until it succeeds.