Permalink
Browse files

(Pessimistically) ensure the connection is, indeed, live.

  • Loading branch information...
1 parent 4dcdaac commit ff8c546ea677ed0bef64b3a9fd8a4c84d440218d @kgaughan committed Sep 27, 2012
Showing with 32 additions and 14 deletions.
  1. +24 −13 dbkit.py
  2. +8 −1 tests/fakedb.py
View
@@ -200,15 +200,13 @@ class ConnectionMediatorBase(object):
"""
__slots__ = (
- 'OperationalError', 'InterfaceError',
+ 'OperationalError', 'InterfaceError', 'DatabaseError',
'conn', 'depth')
def __init__(self, exceptions):
super(ConnectionMediatorBase, self).__init__()
- # pylint: disable-msg=C0103
- self.OperationalError = exceptions.OperationalError
- # pylint: disable-msg=C0103
- self.InterfaceError = exceptions.InterfaceError
+ for exc in ('OperationalError', 'InterfaceError', 'DatabaseError'):
+ setattr(self, exc, getattr(exceptions, exc))
# The currently acquired connection, or None.
self.conn = None
# When this reaches 0, we release
@@ -265,10 +263,16 @@ def __exit__(self, exc_type, _exc_value, _traceback):
def cursor(self):
try:
- return self.conn.cursor()
- except self.InterfaceError:
+ cursor = self.conn.cursor()
+ cursor.execute('SELECT 1')
+ cursor.fetchall()
+ except (self.InterfaceError, self.DatabaseError):
+ del self.conn
self.conn = self.connect()
- return self.conn.cursor()
+ cursor = self.conn.cursor()
+ cursor.execute('SELECT 1')
+ cursor.fetchall()
+ return cursor
def close(self):
if self.conn is not None:
@@ -305,19 +309,25 @@ def __exit__(self, exc_type, _exc_value, _traceback):
def cursor(self):
try:
- return self.conn.cursor()
- except self.InterfaceError:
+ cursor = self.conn.cursor()
+ cursor.execute('SELECT 1')
+ cursor.fetchall()
+ except (self.InterfaceError, self.DatabaseError):
# Go through each of the remaining connections
attempts_left = self.pool.get_max_reattempts()
while attempts_left > 0:
self.pool.discard()
self.conn = self.pool.acquire()
try:
- return self.conn.cursor()
- except self.InterfaceError:
+ cursor = self.conn.cursor()
+ cursor.execute('SELECT 1')
+ cursor.fetchall()
+ break
+ except (self.InterfaceError, self.DatabaseError):
if attempts_left == 1:
raise
attempts_left -= 1
+ return cursor
def close(self):
# Nothing currently, but may in the future signal to pool to
@@ -458,7 +468,8 @@ def finalise(self):
self._cond.release()
def get_max_reattempts(self):
- return min(self._allocated + 1, self._max_conns)
+ # We retry one extra times to
+ return self._max_conns + 1
def _make_connect(module, args, kwargs):
View
@@ -77,7 +77,11 @@ def close(self):
def execute(self, stmt, args=()):
if not self.valid or not self.connection.valid:
raise InterfaceError()
- stmt_type, = stmt.lstrip().lower().split(' ', 1)
+ stmt = stmt.lstrip().lower()
+ # It's the ping!
+ if stmt == 'select 1':
+ return self
+ stmt_type, = stmt.split(' ', 1)
if stmt_type in ('select', 'update', 'insert', 'delete'):
self.result = None if args is () else args
self.connection.session.append(stmt_type)
@@ -100,6 +104,9 @@ def fetchone(self):
self.result = None
return result
+ def fetchall(self):
+ return ()
+
class Warning(StandardError):
pass

0 comments on commit ff8c546

Please sign in to comment.