From fef9f3d7058e130d6001a28cdfbf1cd1baa8c752 Mon Sep 17 00:00:00 2001 From: Deeman Date: Fri, 20 Feb 2026 19:04:09 +0100 Subject: [PATCH] Fix concurrent DuckDB queries: use cursor() per thread _conn.execute() is not thread-safe for concurrent calls from multiple threads. asyncio.gather submits each analytics query to the thread pool via asyncio.to_thread, causing race conditions that silently returned empty result sets. _conn.cursor() creates an independent cursor that is safe to use from separate threads simultaneously. Co-Authored-By: Claude Opus 4.6 --- web/src/beanflows/analytics.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/src/beanflows/analytics.py b/web/src/beanflows/analytics.py index cc706d7..72980a1 100644 --- a/web/src/beanflows/analytics.py +++ b/web/src/beanflows/analytics.py @@ -57,7 +57,8 @@ async def fetch_analytics(sql: str, params: list | None = None) -> list[dict]: assert _conn is not None, "Analytics DB not initialized — call open_analytics_db() first" def _query(): - result = _conn.execute(sql, params or []) + cursor = _conn.cursor() + result = cursor.execute(sql, params or []) columns = [desc[0] for desc in result.description] return [dict(zip(columns, row)) for row in result.fetchall()]