From 686ae08e13fb7069e108b85103340381afa566c0 Mon Sep 17 00:00:00 2001 From: Forrest Collman Date: Wed, 23 Jul 2025 07:09:44 -0700 Subject: [PATCH 1/4] improved session management --- dynamicannotationdb/database.py | 52 ++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/dynamicannotationdb/database.py b/dynamicannotationdb/database.py index f33e2c7..88f2003 100644 --- a/dynamicannotationdb/database.py +++ b/dynamicannotationdb/database.py @@ -55,15 +55,45 @@ def cached_session(self) -> Session: @contextmanager def session_scope(self): + session = None try: - yield self.cached_session + # Validate and recreate session if needed + if self._cached_session is None or not self._is_session_valid(self._cached_session): + if self._cached_session is not None: + try: + self._cached_session.close() + except Exception: + pass + self._cached_session = None + + session = self.cached_session + yield session except Exception as e: - self.cached_session.rollback() + if session is not None: + try: + session.rollback() + except Exception: + pass logging.exception(f"SQL Error: {e}") raise e finally: - self.cached_session.close() - self._cached_session = None + # Don't close the session - let connection pool manage it + # The session will be reused for subsequent requests + pass + + def _is_session_valid(self, session): + """Check if a SQLAlchemy session is valid and can be used.""" + if session is None: + return False + try: + # Check if session is bound and connection is alive + if not hasattr(session, 'bind') or session.bind is None: + return False + # Try a simple query to test the connection + session.execute("SELECT 1") + return True + except Exception: + return False def commit_session(self): try: @@ -72,9 +102,17 @@ def commit_session(self): self.cached_session.rollback() logging.exception(f"SQL Error: {e}") raise e - finally: - self.cached_session.close() - self._cached_session = None + # Don't close or reset the session - keep it for reuse + + def close_session(self): + """Explicitly close the cached session (for cleanup/shutdown).""" + if self._cached_session is not None: + try: + self._cached_session.close() + except Exception as e: + logging.exception(f"Error closing session: {e}") + finally: + self._cached_session = None def get_table_sql_metadata(self, table_name: str): self.base.metadata.reflect(bind=self.engine) From 7da8d7ebc0c2147115cded89e7de826f1d743c90 Mon Sep 17 00:00:00 2001 From: Forrest Collman Date: Wed, 23 Jul 2025 07:48:50 -0700 Subject: [PATCH 2/4] Update dynamicannotationdb/database.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- dynamicannotationdb/database.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/dynamicannotationdb/database.py b/dynamicannotationdb/database.py index 88f2003..3f00292 100644 --- a/dynamicannotationdb/database.py +++ b/dynamicannotationdb/database.py @@ -81,8 +81,16 @@ def session_scope(self): # The session will be reused for subsequent requests pass - def _is_session_valid(self, session): - """Check if a SQLAlchemy session is valid and can be used.""" + def _is_session_valid(self, session: Session) -> bool: + """ + Check if a SQLAlchemy session is valid and can be used. + + Args: + session (Session): The SQLAlchemy session to validate. + + Returns: + bool: True if the session is valid, False otherwise. + """ if session is None: return False try: From 5c09821dc3790482a4a223d8b5699f21fb24ff03 Mon Sep 17 00:00:00 2001 From: Forrest Collman Date: Wed, 23 Jul 2025 07:49:13 -0700 Subject: [PATCH 3/4] Update dynamicannotationdb/database.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- dynamicannotationdb/database.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dynamicannotationdb/database.py b/dynamicannotationdb/database.py index 3f00292..6ea86a1 100644 --- a/dynamicannotationdb/database.py +++ b/dynamicannotationdb/database.py @@ -98,7 +98,7 @@ def _is_session_valid(self, session: Session) -> bool: if not hasattr(session, 'bind') or session.bind is None: return False # Try a simple query to test the connection - session.execute("SELECT 1") + session.get_bind().execute("SELECT 1") return True except Exception: return False From d89543895631640d8705cabb4cf96f85af65a98f Mon Sep 17 00:00:00 2001 From: Forrest Collman Date: Wed, 23 Jul 2025 07:51:15 -0700 Subject: [PATCH 4/4] update python version to test --- .github/workflows/dynamic_annotation_db _ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dynamic_annotation_db _ci.yml b/.github/workflows/dynamic_annotation_db _ci.yml index 5995d96..f58677e 100644 --- a/.github/workflows/dynamic_annotation_db _ci.yml +++ b/.github/workflows/dynamic_annotation_db _ci.yml @@ -30,10 +30,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up Python 3.7 + - name: Set up Python 3.12 uses: actions/setup-python@v5 with: - python-version: 3.7 + python-version: 3.12 - uses: actions/cache@v4 with: