diff --git a/neutron/db/api.py b/neutron/db/api.py index 6fe5aa933c2..878291135a2 100644 --- a/neutron/db/api.py +++ b/neutron/db/api.py @@ -37,7 +37,10 @@ MAX_RETRIES = 10 def is_retriable(e): - return _is_nested_instance(e, (db_exc.DBDeadlock, exc.StaleDataError)) + if _is_nested_instance(e, (db_exc.DBDeadlock, exc.StaleDataError)): + return True + # looking savepoints mangled by deadlocks. see bug/1590298 for details. + return _is_nested_instance(e, db_exc.DBError) and '1305' in str(e) is_deadlock = moves.moved_function(is_retriable, 'is_deadlock', __name__, message='use "is_retriable" instead', diff --git a/neutron/tests/unit/db/test_api.py b/neutron/tests/unit/db/test_api.py index 6402de5fd27..838191330be 100644 --- a/neutron/tests/unit/db/test_api.py +++ b/neutron/tests/unit/db/test_api.py @@ -82,3 +82,8 @@ class TestDeadLockDecorator(base.BaseTestCase): e = exceptions.MultipleExceptions([ValueError(), db_exc.DBDeadlock()]) with testtools.ExpectedException(exceptions.MultipleExceptions): self._decorated_function(db_api.MAX_RETRIES + 1, e) + + def test_mysql_savepoint_error(self): + e = db_exc.DBError("(pymysql.err.InternalError) (1305, u'SAVEPOINT " + "sa_savepoint_1 does not exist')") + self.assertIsNone(self._decorated_function(1, e))