From 2aac8c2e02457de9de0eef2f044f3f005cca37c8 Mon Sep 17 00:00:00 2001 From: CleverThis Date: Tue, 5 May 2026 04:18:47 +0000 Subject: [PATCH] fix(database/migration_runner): add check_same_thread=False to get_current_revision() SQLite engine MigrationRunner.get_current_revision() was creating a SQLite engine without connect_args={'check_same_thread': False}, causing ProgrammingError when called from a different thread than the one that created the engine. This is now consistent with init_or_upgrade() which correctly passes check_same_thread=False for all SQLite engines. Added a Behave scenario to verify that get_current_revision() passes check_same_thread=False when creating a SQLite engine. ISSUES CLOSED: #10952 --- features/consolidated_misc.feature | 6 ++++++ features/steps/migration_runner_steps.py | 11 +++++++++++ .../infrastructure/database/migration_runner.py | 8 +++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/features/consolidated_misc.feature b/features/consolidated_misc.feature index f1caf6b8e..7649d56ea 100644 --- a/features/consolidated_misc.feature +++ b/features/consolidated_misc.feature @@ -1714,6 +1714,12 @@ Feature: Consolidated Misc And the temporary connection should be closed afterward + Scenario: get_current_revision uses check_same_thread=False for SQLite engines + Given a migration runner configured for "sqlite:///:memory:" + When I request the current revision from the database + Then the SQLite engine for get_current_revision should use check_same_thread=False + + Scenario: File-based SQLite database directory is created if missing Given a migration runner configured for "sqlite:///tmp/test-db/mydb.db" When I initialize or upgrade a file-based SQLite database diff --git a/features/steps/migration_runner_steps.py b/features/steps/migration_runner_steps.py index ec0018297..beef1f61a 100644 --- a/features/steps/migration_runner_steps.py +++ b/features/steps/migration_runner_steps.py @@ -316,6 +316,17 @@ def step_then_temp_connection_closed(context) -> None: assert context.current_rev_fake_engine.connections[0].exit_called is True +@then("the SQLite engine for get_current_revision should use check_same_thread=False") +def step_then_get_current_revision_check_same_thread(context) -> None: + _url, kwargs = context.current_rev_create_call + assert "connect_args" in kwargs, ( + "Expected connect_args to be passed to create_engine for SQLite" + ) + assert kwargs["connect_args"].get("check_same_thread") is False, ( + "Expected check_same_thread=False in connect_args for SQLite engine" + ) + + @when("I initialize or upgrade a file-based SQLite database") def step_when_init_file_based_sqlite(context) -> None: import shutil diff --git a/src/cleveragents/infrastructure/database/migration_runner.py b/src/cleveragents/infrastructure/database/migration_runner.py index c731c1c50..8f8393cb3 100644 --- a/src/cleveragents/infrastructure/database/migration_runner.py +++ b/src/cleveragents/infrastructure/database/migration_runner.py @@ -154,7 +154,13 @@ class MigrationRunner: Returns: Current revision ID or None if no migrations have been applied """ - engine = create_engine(self.database_url) + if self.database_url.startswith("sqlite"): + engine = create_engine( + self.database_url, + connect_args={"check_same_thread": False}, + ) + else: + engine = create_engine(self.database_url) with engine.connect() as connection: context = MigrationContext.configure(connection) return context.get_current_revision()