@@ -103,8 +103,8 @@ class InvalidCursor(SteadyDBError):
103103 """Database cursor is invalid."""
104104
105105
106- def connect (creator , maxusage = None , setsession = None , failures = None ,
107- closeable = True , ping = None , * args , ** kwargs ):
106+ def connect (creator , maxusage = None , setsession = None ,
107+ failures = None , ping = 1 , closeable = True , * args , ** kwargs ):
108108 """A tough version of the connection constructor of a DB-API 2 module.
109109
110110 creator: either an arbitrary function returning new DB-API 2 compliant
@@ -118,25 +118,27 @@ def connect(creator, maxusage=None, setsession=None, failures=None,
118118 failures: an optional exception class or a tuple of exception classes
119119 for which the failover mechanism shall be applied, if the default
120120 (OperationalError, InternalError) is not adequate
121+ ping: determines when the connection should be checked with ping()
122+ (0 = None = never, 1 = default = when _ping_check() is called,
123+ 2 = whenever a cursor is created, 4 = when a query is executed,
124+ 7 = always, and all other bit combinations of these values)
121125 closeable: if this is set to false, then closing the connection will
122126 be silently ignored, but by default the connection can be closed
123- ping: determines when the connection should be checked with ping()
124- (0 = default = never, 1 = on cursor(), 2 = on execute(), 3 = both)
125127 args, kwargs: the parameters that shall be passed to the creator
126128 function or the connection constructor of the DB-API 2 module
127129
128130 """
129- return SteadyDBConnection (creator , maxusage , setsession , failures ,
130- closeable , ping , * args , ** kwargs )
131+ return SteadyDBConnection (creator , maxusage , setsession ,
132+ failures , ping , closeable , * args , ** kwargs )
131133
132134
133135class SteadyDBConnection :
134136 """A "tough" version of DB-API 2 connections."""
135137
136138 version = __version__
137139
138- def __init__ (self , creator , maxusage = None , setsession = None , failures = None ,
139- closeable = True , ping = None , * args , ** kwargs ):
140+ def __init__ (self , creator , maxusage = None , setsession = None ,
141+ failures = None , ping = 1 , closeable = True , * args , ** kwargs ):
140142 """Create a "tough" DB-API 2 connection."""
141143 # basic initialization to make finalizer work
142144 self ._con = None
@@ -176,8 +178,8 @@ def __init__(self, creator, maxusage=None, setsession=None, failures=None,
176178 failures , tuple ) and not issubclass (failures , Exception ):
177179 raise TypeError ("'failures' must be a tuple of exceptions." )
178180 self ._failures = failures
181+ self ._ping = isinstance (ping , int ) and ping or 0
179182 self ._closeable = closeable
180- self ._ping = ping or 0
181183 self ._args , self ._kwargs = args , kwargs
182184 self ._store (self ._create ())
183185
@@ -298,6 +300,38 @@ def _close(self):
298300 pass
299301 self ._closed = True
300302
303+ def _ping_check (self , ping = 1 , reconnect = True ):
304+ """Check whether the connection is still alive using ping().
305+
306+ If the the underlying connection is not active and the ping
307+ parameter is set accordingly, the connection will be recreated.
308+
309+ """
310+ if ping & self ._ping :
311+ try : # if possible, ping the connection
312+ alive = self ._con .ping ()
313+ except (AttributeError , IndexError , TypeError , ValueError ):
314+ self ._ping = 0 # ping() is not available
315+ alive = None
316+ reconnect = False
317+ except Exception :
318+ alive = False
319+ else :
320+ if alive is None :
321+ alive = True
322+ if alive :
323+ reconnect = False
324+ if reconnect :
325+ try : # try to reopen the connection
326+ con = self ._create ()
327+ except Exception :
328+ pass
329+ else :
330+ self ._close ()
331+ self ._store (con )
332+ alive = True
333+ return alive
334+
301335 def dbapi (self ):
302336 """Return the underlying DB-API 2 module of the connection."""
303337 if self ._dbapi is None :
@@ -344,39 +378,29 @@ def _cursor(self, *args, **kwargs):
344378 """A "tough" version of the method cursor()."""
345379 # The args and kwargs are not part of the standard,
346380 # but some database modules seem to use these.
381+ self ._ping_check (2 )
347382 try :
348383 if self ._maxusage :
349384 if self ._usage >= self ._maxusage :
350385 # the connection was used too often
351386 raise self ._failure
352- con = self ._con
353- if self ._ping & 1 :
354- try : # if possible, ping the connection
355- ping = con .ping ()
356- except (AttributeError , TypeError , ValueError ):
357- self ._ping = 0 # ping() is not available
358- ping = None
359- except Exception :
360- ping = False
361- if ping is not None and not ping :
362- raise self ._failure # connection is dead
363- cursor = con .cursor (* args , ** kwargs ) # try to get a cursor
387+ cursor = self ._con .cursor (* args , ** kwargs ) # try to get a cursor
364388 except self ._failures , error : # error in getting cursor
365389 try : # try to reopen the connection
366- con2 = self ._create ()
390+ con = self ._create ()
367391 except Exception :
368392 pass
369393 else :
370394 try : # and try one more time to get a cursor
371- cursor = con2 .cursor (* args , ** kwargs )
395+ cursor = con .cursor (* args , ** kwargs )
372396 except Exception :
373397 pass
374398 else :
375399 self ._close ()
376- self ._store (con2 )
400+ self ._store (con )
377401 return cursor
378402 try :
379- con2 .close ()
403+ con .close ()
380404 except Exception :
381405 pass
382406 raise error # reraise the original error again
@@ -455,21 +479,12 @@ def _get_tough_method(self, name):
455479 def tough_method (* args , ** kwargs ):
456480 execute = name .startswith ('execute' )
457481 con = self ._con
482+ con ._ping_check (4 )
458483 try :
459484 if con ._maxusage :
460485 if con ._usage >= con ._maxusage :
461486 # the connection was used too often
462487 raise con ._failure
463- if con ._ping & 2 :
464- try : # if possible, ping the connection
465- ping = con ._con .ping ()
466- except (AttributeError , TypeError , ValueError ):
467- self ._ping = 0 # ping() is not available
468- ping = None
469- except Exception :
470- ping = False
471- if ping is not None and not ping :
472- raise con ._failure # connection is dead
473488 if execute :
474489 self ._setsizes ()
475490 method = getattr (self ._cursor , name )
0 commit comments