Discard disconnected connection from the pool

When a connection in the pool is disconnected, it stays in the pool and it may
still be served.
Using such connection raise an OperationalError and so the request is retried
but before that the connection is put back to the pool. So we may get it back
again.
It is not possible to distinct between an OperationalError due to a
disconnection or due to a isolation error for example.
So with the current design of Transaction API, an OperationalError always put
back the connection to the pool.
This main that we can only ensure that the connections served are still
connected by executing a simple query. And close connections that are failing.

Closes #12452
This commit is contained in:
Cédric Krier
2023-08-04 15:59:35 +02:00
parent d6a92dc606
commit e2676bcd85
+13 -6
View File
@@ -255,10 +255,10 @@ class Database(DatabaseInterface):
return self
def get_connection(self, autocommit=False, readonly=False):
for count in range(config.getint('database', 'retry'), -1, -1):
retry = max(config.getint('database', 'retry'), _maxconn)
for count in range(retry, -1, -1):
try:
conn = self._connpool.getconn()
break
except PoolError:
if count and not self._connpool.closed:
logger.info('waiting a connection')
@@ -269,10 +269,17 @@ class Database(DatabaseInterface):
logger.error(
'connection to "%s" failed', self.name, exc_info=True)
raise
conn.set_session(
isolation_level=ISOLATION_LEVEL_REPEATABLE_READ,
readonly=readonly,
autocommit=autocommit)
try:
conn.set_session(
isolation_level=ISOLATION_LEVEL_REPEATABLE_READ,
readonly=readonly,
autocommit=autocommit)
# Detect disconnection
conn.cursor().execute('SELECT 1')
except DatabaseOperationalError:
self._connpool.putconn(conn, close=True)
continue
break
return conn
def put_connection(self, connection, close=False):