Merge "Add a _retry_on_deadlock decorator"

This commit is contained in:
Jenkins 2014-07-16 17:44:41 +00:00 committed by Gerrit Code Review
commit b7d07d4c6f
2 changed files with 40 additions and 0 deletions

View File

@ -21,6 +21,7 @@
"""Defines interface for DB access.""" """Defines interface for DB access."""
from oslo.config import cfg from oslo.config import cfg
from retrying import retry
import six import six
from six.moves import xrange from six.moves import xrange
import sqlalchemy import sqlalchemy
@ -52,6 +53,15 @@ CONF.import_opt('connection', 'glance.openstack.common.db.options',
_FACADE = None _FACADE = None
def _retry_on_deadlock(exc):
"""Decorator to retry a DB API call if Deadlock was received."""
if isinstance(exc, db_exception.DBDeadlock):
LOG.warn(_("Deadlock detected. Retrying..."))
return True
return False
def _create_facade_lazily(): def _create_facade_lazily():
global _FACADE global _FACADE
if _FACADE is None: if _FACADE is None:
@ -632,6 +642,8 @@ def _update_values(image_ref, values):
setattr(image_ref, k, values[k]) setattr(image_ref, k, values[k])
@retry(retry_on_exception=_retry_on_deadlock, wait_fixed=500,
stop_max_attempt_number=50)
def _image_update(context, values, image_id, purge_props=False, def _image_update(context, values, image_id, purge_props=False,
from_state=None): from_state=None):
""" """

View File

@ -24,6 +24,8 @@ from glance.common import exception
from glance.common import utils from glance.common import utils
import glance.context import glance.context
import glance.db import glance.db
from glance.db.sqlalchemy import api
from glance.openstack.common.db import exception as db_exc
import glance.tests.unit.utils as unit_test_utils import glance.tests.unit.utils as unit_test_utils
import glance.tests.utils as test_utils import glance.tests.utils as test_utils
@ -689,3 +691,29 @@ class TestTaskRepo(test_utils.BaseTestCase):
self.assertRaises(exception.NotFound, self.assertRaises(exception.NotFound,
self.task_repo.get, self.task_repo.get,
task.task_id) task.task_id)
class RetryOnDeadlockTestCase(test_utils.BaseTestCase):
def test_raise_deadlock(self):
class TestException(Exception):
pass
self.attempts = 3
def _mock_get_session():
def _raise_exceptions():
self.attempts -= 1
if self.attempts <= 0:
raise TestException("Exit")
raise db_exc.DBDeadlock("Fake Exception")
return _raise_exceptions
with mock.patch.object(api, 'get_session') as sess:
sess.side_effect = _mock_get_session()
try:
api._image_update(None, {}, 'fake-id')
except TestException:
self.assertEqual(sess.call_count, 3)