Merge "Separate exception class for retriables in callbacks"

This commit is contained in:
Jenkins 2016-06-23 18:12:44 +00:00 committed by Gerrit Code Review
commit 53d9e05def
3 changed files with 29 additions and 0 deletions

View File

@ -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).

View File

@ -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

View File

@ -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