Skip to content

fix(connection): don't block in set_query_timeout() while a query runs - #67

Open
zahariash wants to merge 1 commit into
LadybugDB:mainfrom
zahariash:fix/nonblocking-set-query-timeout
Open

zahariash wants to merge 1 commit into
LadybugDB:mainfrom
zahariash:fix/nonblocking-set-query-timeout

Conversation

@zahariash

Copy link
Copy Markdown
Contributor

This work was produced with the help of language models.

The engine applies the query timeout and per-query thread limit under the mutex a running query holds for its whole duration, so Connection.set_query_timeout() and set_max_threads_for_exec() blocked until the running query finished, and the pybind bindings held the GIL meanwhile, freezing every Python thread: AsyncConnection.set_query_timeout() with 4 long queries in flight froze the event loop for 12-13 s (CPython 3.13/3.14).

Fix. Both setters record the value and return immediately; it is applied before the connection's next execute(), query_as_arrow() or Arrow-table call, latest value wins. The two pybind bindings release the GIL, so a thread that does wait no longer stalls the others.

Tests. Two new tests on a fresh connection: the setters return while a query runs (fails on main: 6.05 s), and applying a pending setting while a query runs does not stall other threads (fails with the old bindings: 6.4 s stall). Both pass here on pybind and C-API. Full suites: no new failures.

Fixes #63

The engine applies the query timeout and the per-query thread limit under the
same per-connection lock that a running query holds for its whole duration.
Connection.set_query_timeout() and set_max_threads_for_exec() called the
engine right away, so with a query running on the connection they blocked
until it finished. On the pybind backend they also held the GIL while waiting,
which froze every Python thread, including an asyncio event loop that called
AsyncConnection.set_query_timeout().

Both setters now record the value and return immediately. The value is
applied before the next execute(), query_as_arrow() or Arrow-table call on
that connection, by one thread at a time so that the latest value wins. The
pybind bindings of the two native setters release the GIL, so a thread that
does wait for the lock does not stall other threads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

set_query_timeout() blocks while a query runs and stalls every Python thread

1 participant