Merge "Separate exception class for retriables in callbacks"
This commit is contained in:
commit
53d9e05def
|
@ -18,6 +18,7 @@ from oslo_utils import reflection
|
||||||
from neutron._i18n import _LE
|
from neutron._i18n import _LE
|
||||||
from neutron.callbacks import events
|
from neutron.callbacks import events
|
||||||
from neutron.callbacks import exceptions
|
from neutron.callbacks import exceptions
|
||||||
|
from neutron.db import api as db_api
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -106,6 +107,7 @@ class CallbacksManager(object):
|
||||||
del self._callbacks[resource][event][callback_id]
|
del self._callbacks[resource][event][callback_id]
|
||||||
del self._index[callback_id]
|
del self._index[callback_id]
|
||||||
|
|
||||||
|
@db_api.reraise_as_retryrequest
|
||||||
def notify(self, resource, event, trigger, **kwargs):
|
def notify(self, resource, event, trigger, **kwargs):
|
||||||
"""Notify all subscribed callback(s).
|
"""Notify all subscribed callback(s).
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ from oslo_db import exception as db_exc
|
||||||
from oslo_db.sqlalchemy import enginefacade
|
from oslo_db.sqlalchemy import enginefacade
|
||||||
from oslo_utils import excutils
|
from oslo_utils import excutils
|
||||||
import osprofiler.sqlalchemy
|
import osprofiler.sqlalchemy
|
||||||
|
import six
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
from sqlalchemy.orm import exc
|
from sqlalchemy.orm import exc
|
||||||
|
|
||||||
|
@ -55,6 +56,21 @@ retry_db_errors = oslo_db_api.wrap_db_retry(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def reraise_as_retryrequest(f):
|
||||||
|
"""Packs retriable exceptions into a RetryRequest."""
|
||||||
|
|
||||||
|
@six.wraps(f)
|
||||||
|
def wrapped(*args, **kwargs):
|
||||||
|
try:
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
except Exception as e:
|
||||||
|
with excutils.save_and_reraise_exception() as ctx:
|
||||||
|
if is_retriable(e):
|
||||||
|
ctx.reraise = False
|
||||||
|
raise db_exc.RetryRequest(e)
|
||||||
|
return wrapped
|
||||||
|
|
||||||
|
|
||||||
def _is_nested_instance(e, etypes):
|
def _is_nested_instance(e, etypes):
|
||||||
"""Check if exception or its inner excepts are an instance of etypes."""
|
"""Check if exception or its inner excepts are an instance of etypes."""
|
||||||
return (isinstance(e, etypes) or
|
return (isinstance(e, etypes) or
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
from oslo_db import exception as db_exc
|
||||||
|
|
||||||
from neutron.callbacks import events
|
from neutron.callbacks import events
|
||||||
from neutron.callbacks import exceptions
|
from neutron.callbacks import exceptions
|
||||||
|
@ -35,6 +36,10 @@ def callback_raise(*args, **kwargs):
|
||||||
raise Exception()
|
raise Exception()
|
||||||
|
|
||||||
|
|
||||||
|
def callback_raise_retriable(*args, **kwargs):
|
||||||
|
raise db_exc.DBDeadlock()
|
||||||
|
|
||||||
|
|
||||||
class CallBacksManagerTestCase(base.BaseTestCase):
|
class CallBacksManagerTestCase(base.BaseTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -173,6 +178,12 @@ class CallBacksManagerTestCase(base.BaseTestCase):
|
||||||
resources.PORT, events.BEFORE_CREATE, self)
|
resources.PORT, events.BEFORE_CREATE, self)
|
||||||
self.assertIsInstance(e.errors[0], exceptions.NotificationError)
|
self.assertIsInstance(e.errors[0], exceptions.NotificationError)
|
||||||
|
|
||||||
|
def test_notify_handle_retriable_exception(self):
|
||||||
|
self.manager.subscribe(
|
||||||
|
callback_raise_retriable, resources.PORT, events.BEFORE_CREATE)
|
||||||
|
self.assertRaises(db_exc.RetryRequest, self.manager.notify,
|
||||||
|
resources.PORT, events.BEFORE_CREATE, self)
|
||||||
|
|
||||||
def test_notify_called_once_with_no_failures(self):
|
def test_notify_called_once_with_no_failures(self):
|
||||||
with mock.patch.object(self.manager, '_notify_loop') as n:
|
with mock.patch.object(self.manager, '_notify_loop') as n:
|
||||||
n.return_value = False
|
n.return_value = False
|
||||||
|
|
Loading…
Reference in New Issue