Add _wrap_db_error() support to Session.commit()

This patch adds _wrap_db_error() to session.commit(),
which has been observed to be a common point of failure for
deadlock exceptions.   In order to achieve this, the
_wrap_db_error() decorator itself also needed to propagate an
existing DBError, as it is the case that SQLAlchemy's
session.commit() calls into the session.flush() method.
Tests are added to exercise both the nesting of _wrap_db_error()
when a flush() inside commit() raises an exception, as well
as when commit() alone raises an exception that the error
is wrapped as expected.

Tests are omitted here as we are relying upon the tests
that were added to the corresponding oslo-incubator code.

Closes-bug: #1370191
Change-Id: I91510a2b864f0c1b73cfae18f271e94334714dce
This commit is contained in:
Mike Bayer 2014-09-22 16:53:55 -04:00
parent b5958c7450
commit 3371ad81ba
1 changed files with 8 additions and 0 deletions

View File

@ -455,6 +455,10 @@ def _wrap_db_error(f):
# unique constraint, from error message.
_raise_if_duplicate_entry_error(e, self.bind.dialect.name)
raise exception.DBError(e)
except exception.DBError:
# note(zzzeek) - if _wrap_db_error is applied to nested functions,
# ensure an existing DBError is propagated outwards
raise
except Exception as e:
LOG.exception(_LE('DB exception wrapped.'))
raise exception.DBError(e)
@ -692,6 +696,10 @@ class Session(sqlalchemy.orm.session.Session):
def execute(self, *args, **kwargs):
return super(Session, self).execute(*args, **kwargs)
@_wrap_db_error
def commit(self, *args, **kwargs):
return super(Session, self).commit(*args, **kwargs)
def get_maker(engine, autocommit=True, expire_on_commit=False):
"""Return a SQLAlchemy sessionmaker using the given engine."""