From 5f458da0e16ce99a5acfaba5d01b671d47fe151d Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Tue, 3 Feb 2026 17:58:04 +0100 Subject: [PATCH 1/2] Make database heartbeat more robust Should fix https://github.com/galaxyproject/galaxy/issues/21713 --- lib/galaxy/model/database_heartbeat.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/galaxy/model/database_heartbeat.py b/lib/galaxy/model/database_heartbeat.py index abffbf646257..c16a8c64de03 100644 --- a/lib/galaxy/model/database_heartbeat.py +++ b/lib/galaxy/model/database_heartbeat.py @@ -11,6 +11,7 @@ ) from galaxy.model import WorkerProcess +from galaxy.model.base import check_database_connection from galaxy.model.orm.now import now log = logging.getLogger(__name__) @@ -106,7 +107,11 @@ def update_watcher_designation(self): def send_database_heartbeat(self): if self.active: while not self.exit.is_set(): - self.update_watcher_designation() + check_database_connection(self.sa_session) + try: + self.update_watcher_designation() + except Exception: + log.exception("Error sending database heartbeat for server '%s'", self.server_name) self.exit.wait(self.heartbeat_interval) def _delete_worker_process(self): From e69ff8ceb2afb825733cabb003d8841c2d9f6d7a Mon Sep 17 00:00:00 2001 From: mvdbeek Date: Tue, 3 Feb 2026 21:22:48 +0100 Subject: [PATCH 2/2] Fix connection leak in check_database_connection Only check session.connection().invalidated when there's an existing transaction. This avoids checking out a new connection from the pool that would never be returned, causing "too many clients" errors during integration tests. Co-Authored-By: Claude Opus 4.5 --- lib/galaxy/model/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/galaxy/model/base.py b/lib/galaxy/model/base.py index a100f044a07a..8b14970fc303 100644 --- a/lib/galaxy/model/base.py +++ b/lib/galaxy/model/base.py @@ -61,7 +61,7 @@ def check_database_connection(session): if isinstance(session, scoped_session): session = session() trans = session.get_transaction() - if (trans and not trans.is_active) or session.connection().invalidated: + if trans and (not trans.is_active or session.connection().invalidated): session.rollback() log.error("Database transaction rolled back due to inactive session transaction or invalid connection state.")