util.failover: re-raise exceptions on failure
This commit is contained in:
parent
21b09a7451
commit
cba7816caf
2 changed files with 19 additions and 13 deletions
|
@ -7,11 +7,12 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class FailoverException(Exception):
|
class FailoverException(Exception):
|
||||||
""" Exception raised when an operation should be retried by the failover decorator. """
|
""" Exception raised when an operation should be retried by the failover decorator.
|
||||||
def __init__(self, return_value, message):
|
Wraps the exception of the initial failure.
|
||||||
|
"""
|
||||||
|
def __init__(self, exception):
|
||||||
super(FailoverException, self).__init__()
|
super(FailoverException, self).__init__()
|
||||||
self.return_value = return_value
|
self.exception = exception
|
||||||
self.message = message
|
|
||||||
|
|
||||||
def failover(func):
|
def failover(func):
|
||||||
""" Wraps a function such that it can be retried on specified failures.
|
""" Wraps a function such that it can be retried on specified failures.
|
||||||
|
@ -21,9 +22,10 @@ def failover(func):
|
||||||
@failover
|
@failover
|
||||||
def get_google(scheme, use_www=False):
|
def get_google(scheme, use_www=False):
|
||||||
www = 'www.' if use_www else ''
|
www = 'www.' if use_www else ''
|
||||||
r = requests.get(scheme + '://' + www + 'google.com')
|
try:
|
||||||
if r.status_code != 200:
|
r = requests.get(scheme + '://' + www + 'google.com')
|
||||||
raise FailoverException('non 200 response from Google' )
|
except requests.RequestException as ex:
|
||||||
|
raise FailoverException(ex)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def GooglePingTest():
|
def GooglePingTest():
|
||||||
|
@ -41,8 +43,8 @@ def failover(func):
|
||||||
try:
|
try:
|
||||||
return func(*arg_set[0], **arg_set[1])
|
return func(*arg_set[0], **arg_set[1])
|
||||||
except FailoverException as ex:
|
except FailoverException as ex:
|
||||||
logger.debug('failing over: %s', ex.message)
|
logger.debug('failing over')
|
||||||
return_value = ex.return_value
|
exception = ex.exception
|
||||||
continue
|
continue
|
||||||
return return_value
|
raise exception
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
|
@ -2,6 +2,9 @@ import pytest
|
||||||
|
|
||||||
from util.failover import failover, FailoverException
|
from util.failover import failover, FailoverException
|
||||||
|
|
||||||
|
class FinishedException(Exception):
|
||||||
|
""" Exception raised at the end of every iteration to force failover. """
|
||||||
|
|
||||||
|
|
||||||
class Counter(object):
|
class Counter(object):
|
||||||
""" Wraps a counter in an object so that it'll be passed by reference. """
|
""" Wraps a counter in an object so that it'll be passed by reference. """
|
||||||
|
@ -18,7 +21,7 @@ def my_failover_func(i, should_raise=None):
|
||||||
i.increment()
|
i.increment()
|
||||||
if should_raise is not None:
|
if should_raise is not None:
|
||||||
raise should_raise()
|
raise should_raise()
|
||||||
raise FailoverException(None, 'incrementing')
|
raise FailoverException(FinishedException())
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('stop_on,exception', [
|
@pytest.mark.parametrize('stop_on,exception', [
|
||||||
|
@ -40,5 +43,6 @@ def test_readonly_failover(stop_on, exception):
|
||||||
with pytest.raises(exception):
|
with pytest.raises(exception):
|
||||||
my_failover_func(*arg_sets)
|
my_failover_func(*arg_sets)
|
||||||
else:
|
else:
|
||||||
my_failover_func(*arg_sets)
|
with pytest.raises(FinishedException):
|
||||||
assert counter.calls == stop_on
|
my_failover_func(*arg_sets)
|
||||||
|
assert counter.calls == stop_on
|
||||||
|
|
Reference in a new issue