details: https://code.tryton.org/tryton/commit/7df2a71c0551
branch: default
user: Cédric Krier <[email protected]>
date: Tue Nov 25 15:05:02 2025 +0100
description:
Use psycopg_pool resize to clear unused database connections
diffstat:
trytond/trytond/backend/postgresql/database.py | 70 ++++++++++++++-----------
1 files changed, 40 insertions(+), 30 deletions(-)
diffs (90 lines):
diff -r 7d95fc685dde -r 7df2a71c0551
trytond/trytond/backend/postgresql/database.py
--- a/trytond/trytond/backend/postgresql/database.py Sun Mar 22 19:53:32
2026 +0100
+++ b/trytond/trytond/backend/postgresql/database.py Tue Nov 25 15:05:02
2025 +0100
@@ -179,6 +179,7 @@
index_translators = []
_lock = RLock()
+ _clean_last = None
_databases = defaultdict(dict)
_connpool = None
_list_cache = {}
@@ -207,39 +208,48 @@
}
def __new__(cls, name=_default_name):
- with cls._lock:
- now = datetime.now()
- databases = cls._databases[os.getpid()]
- timeout = config.getint('database', 'timeout')
+ now = datetime.now()
+ if cls._clean_last is None:
+ cls._clean_last = now
+
+ databases = cls._databases[os.getpid()]
+
+ minconn = config.getint('database', 'minconn', default=1)
+ maxconn = config.getint('database', 'maxconn', default=64)
+ timeout = config.getint('database', 'timeout')
+ last_clean = (now - cls._clean_last).total_seconds()
+ if last_clean > timeout:
for database in list(databases.values()):
if ((now - database._last_use).total_seconds() > timeout
and database.name != name):
- database.close()
- if name in databases:
- inst = databases[name]
- else:
- inst = DatabaseInterface.__new__(cls, name=name)
- minconn = config.getint('database', 'minconn', default=1)
- maxconn = config.getint('database', 'maxconn', default=64)
- kwargs = cls._connection_params(name)
- kwargs['cursor_factory'] = LoggingCursor
- conninfo = kwargs.pop('conninfo')
- try:
- inst._connpool = ConnectionPool(
- conninfo,
- kwargs=kwargs,
- open=True,
- check=ConnectionPool.check_connection,
- min_size=minconn, max_size=maxconn)
- except Exception:
- logger.error(
- 'connection to "%s" failed', name, exc_info=True)
- raise
- else:
- logger.info('connection to "%s" succeeded', name)
- databases[name] = inst
- inst._last_use = datetime.now()
- return inst
+ database._connpool.resize(0, 0)
+
+ if not (inst := databases.get(name)):
+ with cls._lock:
+ if not (inst := databases.get(name)):
+ inst = DatabaseInterface.__new__(cls, name=name)
+ kwargs = cls._connection_params(name)
+ kwargs['cursor_factory'] = LoggingCursor
+ conninfo = kwargs.pop('conninfo')
+ try:
+ inst._connpool = ConnectionPool(
+ conninfo,
+ kwargs=kwargs,
+ open=True,
+ check=ConnectionPool.check_connection,
+ min_size=minconn, max_size=maxconn)
+ except Exception:
+ logger.error(
+ 'connection to "%s" failed', name, exc_info=True)
+ raise
+ else:
+ logger.info('connection to "%s" succeeded', name)
+ databases[name] = inst
+ elif (inst._connpool.min_size != minconn
+ or inst._connpool.max_size != maxconn):
+ inst._connpool.resize(minconn, maxconn)
+ inst._last_use = now
+ return inst
def __init__(self, name=_default_name):
super().__init__(name)