Allow endless retry loops in the utility function
This can be used if an endless loop is needed. Also add a new parameter to allow a maximum backoff sleep time. Partial-Bug: #1690159 Change-Id: Ib544b5bd4781d116dd3dffc8f35f43323cc9e2db
This commit is contained in:
parent
d98455163f
commit
1cf5ccdbdd
@ -649,6 +649,28 @@ class TestRetryDecorator(test.TestCase):
|
|||||||
self.assertRaises(ValueError, raise_unexpected_error)
|
self.assertRaises(ValueError, raise_unexpected_error)
|
||||||
self.assertFalse(mock_sleep.called)
|
self.assertFalse(mock_sleep.called)
|
||||||
|
|
||||||
|
def test_wrong_retries_num(self):
|
||||||
|
self.assertRaises(ValueError, utils.retry, exception.ManilaException,
|
||||||
|
retries=-1)
|
||||||
|
|
||||||
|
def test_max_backoff_sleep(self):
|
||||||
|
self.counter = 0
|
||||||
|
|
||||||
|
with mock.patch.object(time, 'sleep') as mock_sleep:
|
||||||
|
@utils.retry(exception.ManilaException,
|
||||||
|
retries=0,
|
||||||
|
backoff_rate=2,
|
||||||
|
backoff_sleep_max=4)
|
||||||
|
def fails_then_passes():
|
||||||
|
self.counter += 1
|
||||||
|
if self.counter < 5:
|
||||||
|
raise exception.ManilaException(data='fake')
|
||||||
|
else:
|
||||||
|
return 'success'
|
||||||
|
|
||||||
|
self.assertEqual('success', fails_then_passes())
|
||||||
|
mock_sleep.assert_has_calls(map(mock.call, [2, 4, 4, 4]))
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
@ddt.ddt
|
||||||
class RequireDriverInitializedTestCase(test.TestCase):
|
class RequireDriverInitializedTestCase(test.TestCase):
|
||||||
|
@ -432,7 +432,7 @@ class ComparableMixin(object):
|
|||||||
|
|
||||||
|
|
||||||
def retry(exception, interval=1, retries=10, backoff_rate=2,
|
def retry(exception, interval=1, retries=10, backoff_rate=2,
|
||||||
wait_random=False):
|
wait_random=False, backoff_sleep_max=None):
|
||||||
"""A wrapper around retrying library.
|
"""A wrapper around retrying library.
|
||||||
|
|
||||||
This decorator allows to log and to check 'retries' input param.
|
This decorator allows to log and to check 'retries' input param.
|
||||||
@ -445,12 +445,13 @@ def retry(exception, interval=1, retries=10, backoff_rate=2,
|
|||||||
:param interval: param 'interval' is used to calculate time interval
|
:param interval: param 'interval' is used to calculate time interval
|
||||||
between retries:
|
between retries:
|
||||||
interval * backoff_rate ^ previous_attempt_number
|
interval * backoff_rate ^ previous_attempt_number
|
||||||
:param retries: number of retries.
|
:param retries: number of retries. Use 0 for an infinite retry loop.
|
||||||
:param backoff_rate: param 'backoff_rate' is used to calculate time
|
:param backoff_rate: param 'backoff_rate' is used to calculate time
|
||||||
interval between retries:
|
interval between retries:
|
||||||
interval * backoff_rate ^ previous_attempt_number
|
interval * backoff_rate ^ previous_attempt_number
|
||||||
:param wait_random: boolean value to enable retry with random wait timer.
|
:param wait_random: boolean value to enable retry with random wait timer.
|
||||||
|
:param backoff_sleep_max: Maximum number of seconds for the calculated
|
||||||
|
backoff sleep. Use None if no maximum is needed.
|
||||||
"""
|
"""
|
||||||
def _retry_on_exception(e):
|
def _retry_on_exception(e):
|
||||||
return isinstance(e, exception)
|
return isinstance(e, exception)
|
||||||
@ -464,6 +465,9 @@ def retry(exception, interval=1, retries=10, backoff_rate=2,
|
|||||||
else:
|
else:
|
||||||
wait_val = wait_for * 1000.0
|
wait_val = wait_for * 1000.0
|
||||||
|
|
||||||
|
if backoff_sleep_max:
|
||||||
|
wait_val = min(backoff_sleep_max * 1000.0, wait_val)
|
||||||
|
|
||||||
LOG.debug("Sleeping for %s seconds.", (wait_val / 1000.0))
|
LOG.debug("Sleeping for %s seconds.", (wait_val / 1000.0))
|
||||||
return wait_val
|
return wait_val
|
||||||
|
|
||||||
@ -472,11 +476,11 @@ def retry(exception, interval=1, retries=10, backoff_rate=2,
|
|||||||
LOG.debug("Failed attempt %s", previous_attempt_number)
|
LOG.debug("Failed attempt %s", previous_attempt_number)
|
||||||
LOG.debug("Have been at this for %s seconds",
|
LOG.debug("Have been at this for %s seconds",
|
||||||
delay_since_first_attempt)
|
delay_since_first_attempt)
|
||||||
return previous_attempt_number == retries
|
return retries > 0 and previous_attempt_number == retries
|
||||||
|
|
||||||
if retries < 1:
|
if retries < 0:
|
||||||
raise ValueError(_('Retries must be greater than or '
|
raise ValueError(_('Retries must be greater than or '
|
||||||
'equal to 1 (received: %s).') % retries)
|
'equal to 0 (received: %s).') % retries)
|
||||||
|
|
||||||
def _decorator(f):
|
def _decorator(f):
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user