Oslo sync to recover from db2 server disconnects

A checkout listener can be added to sqlalchemy to be able to
handle database disconnect pessimistically and avoid an error in
the event of a DB restart or simply a temp connection issue due
to network glitches. At the moment only mysql is enabled with
this feature. This patch enables db2 as well.

Oslo version in change I5563360b43c4b648f5b035099b0e1d2e71d32503

Partial-Bug: #1231657
Change-Id: I218ef9836f2e0f135897007d2e53354eb1248422
This commit is contained in:
David Peraza 2014-01-08 12:45:13 -06:00
parent 61a715e17e
commit 922f4a28c9
1 changed files with 16 additions and 9 deletions

View File

@ -603,18 +603,24 @@ def _thread_yield(dbapi_con, con_record):
time.sleep(0)
def _ping_listener(dbapi_conn, connection_rec, connection_proxy):
"""Ensures that MySQL connections checked out of the pool are alive.
def _ping_listener(engine, dbapi_conn, connection_rec, connection_proxy):
"""Ensures that MySQL and DB2 connections are alive.
Borrowed from:
http://groups.google.com/group/sqlalchemy/msg/a4ce563d802c929f
"""
cursor = dbapi_conn.cursor()
try:
dbapi_conn.cursor().execute('select 1')
except dbapi_conn.OperationalError as ex:
if ex.args[0] in (2006, 2013, 2014, 2045, 2055):
LOG.warn(_('Got mysql server has gone away: %s'), ex)
raise sqla_exc.DisconnectionError("Database server went away")
ping_sql = 'select 1'
if engine.name == 'ibm_db_sa':
# DB2 requires a table expression
ping_sql = 'select 1 from (values (1)) AS t1'
cursor.execute(ping_sql)
except Exception as ex:
if engine.dialect.is_disconnect(ex, dbapi_conn, cursor):
msg = _('Database server has gone away: %s') % ex
LOG.warning(msg)
raise sqla_exc.DisconnectionError(msg)
else:
raise
@ -671,8 +677,9 @@ def create_engine(sql_connection, sqlite_fk=False):
sqlalchemy.event.listen(engine, 'checkin', _thread_yield)
if 'mysql' in connection_dict.drivername:
sqlalchemy.event.listen(engine, 'checkout', _ping_listener)
if engine.name in ['mysql', 'ibm_db_sa']:
callback = functools.partial(_ping_listener, engine)
sqlalchemy.event.listen(engine, 'checkout', callback)
elif 'sqlite' in connection_dict.drivername:
if not CONF.sqlite_synchronous:
sqlalchemy.event.listen(engine, 'connect',