[API][ADMIN_API]: Improvements to DB driver

* Use native python driver so connection problems don't hang DB
* Change connection algorithm:

Now uses the first DB as a master and will auto failover as required.
It will switch back to the first DB after 60 seconds.

Change-Id: I673503b212f6b6e29306c75beeb3fdbb44bdb488
This commit is contained in:
Andrew Hutchings
2013-09-13 14:22:02 +01:00
parent b81b70852d
commit 55b81ce291
2 changed files with 20 additions and 16 deletions

View File

@@ -18,7 +18,6 @@ from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, backref, sessionmaker, Session
import sqlalchemy.types as types
import time
import random
import ConfigParser
from pecan import conf
import logging
@@ -146,12 +145,14 @@ class HealthMonitor(DeclarativeBase):
class RoutingSession(Session):
""" If an engine is already in use, re-use it. Otherwise we can end up
with deadlocks in Galera, see http://tinyurl.com/9h6qlly
switch engines every 60 seconds of idle time """
""" Try to use the first engine provided. If this fails use the next in
sequence and so on. Reset to the first after 60 seconds
we do this because we can end up with deadlocks in Galera, see
http://tinyurl.com/9h6qlly """
engines = []
last_engine = None
engines = {}
engines_count = 0
use_engine = 0
last_engine_time = 0
def get_bind(self, mapper=None, clause=None):
@@ -159,14 +160,12 @@ class RoutingSession(Session):
self._build_engines()
if (
RoutingSession.last_engine
RoutingSession.use_engine > 0
and time.time() < RoutingSession.last_engine_time + 60
):
RoutingSession.last_engine_time = time.time()
return RoutingSession.last_engine
engine = random.choice(RoutingSession.engines)
RoutingSession.last_engine = engine
RoutingSession.last_engine_time = time.time()
RoutingSession.use_engine = 0
engine = RoutingSession.engines[RoutingSession.use_engine]
return engine
def _build_engines(self):
@@ -175,7 +174,7 @@ class RoutingSession(Session):
for section in conf.database:
db_conf = config._sections[section]
conn_string = '''mysql://%s:%s@%s:%d/%s''' % (
conn_string = '''mysql+mysqlconnector://%s:%s@%s:%d/%s''' % (
db_conf['username'],
db_conf['password'],
db_conf['host'],
@@ -199,7 +198,8 @@ class RoutingSession(Session):
conn_string, isolation_level="READ COMMITTED",
pool_size=20, pool_recycle=3600
)
RoutingSession.engines.append(engine)
RoutingSession.engines[RoutingSession.engines_count] = engine
RoutingSession.engines_count += 1
class db_session(object):
@@ -216,10 +216,14 @@ class db_session(object):
except:
self.logger.error(
'Could not connect to DB server: {0}'.format(
RoutingSession.last_engine.url
RoutingSession.engines[RoutingSession.use_engine].url
)
)
RoutingSession.last_engine = None
RoutingSession.last_engine_time = time.time()
if RoutingSession.use_engine == RoutingSession.engines_count:
RoutingSession.use_engine = 0
else:
RoutingSession.use_engine += 1
self.logger.error('Could not connect to any DB server')
return None