Cursor.close() leaks server-side handle for async commands that were never fetched (#791)#873
Open
peco-engineer-bot[bot] wants to merge 2 commits into
Open
Cursor.close() leaks server-side handle for async commands that were never fetched (#791)#873peco-engineer-bot[bot] wants to merge 2 commits into
peco-engineer-bot[bot] wants to merge 2 commits into
Conversation
…never fetched (#791) Signed-off-by: peco-engineer-bot[bot] <3815206+peco-engineer-bot[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Verdict: 1 Low
Looks good — the fix correctly closes the leaked server-side handle for async-submitted commands that were never fetched by issuing backend.close_command() in the new elif branch, guarded by try/except and reordering active_command_id = None to after the close. logger is defined in the module, all backends implement close_command(command_id), and there's no double-close risk since the branch only fires when active_result_set is None. One low-severity note on E2E coverage (Thrift-only) below.
Addresses: - #3606905116 at tests/e2e/test_driver.py:346 Signed-off-by: peco-engineer-bot[bot] <peco-engineer-bot[bot]@users.noreply.github.com>
| [ | ||
| {}, | ||
| { | ||
| "use_sea": True, |
Contributor
There was a problem hiding this comment.
We should never assign use_sea, there are only 2 active modes either default(thrift), or use_kernel which use kernel.
eric-wang-1990
had a problem deploying
to
azure-prod
July 18, 2026 02:01 — with
GitHub Actions
Failure
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Automated fix for #791 — Cursor.close() leaks server-side handle for async commands that were never fetched.
Fixed Cursor.close() in src/databricks/sql/client.py to call backend.close_command(active_command_id) when active_result_set is None but a command id exists (the async-submit-without-fetch case), so the server-side handle no longer leaks; the call is wrapped in a try/except that logs a warning to stay safe across Thrift/SEA/kernel backends. Verified via the live E2E test and two unit tests.
Root cause & plan
Root cause: Cursor.close() in src/databricks/sql/client.py (lines ~1707-1712) sets self.open=False, nulls self.active_command_id, and only closes self.active_result_set via _close_and_clear_active_result_set(). For an async submission (execute_async / execute(..., async_op=True)) where get_async_execution_result() was never called, active_result_set is None, so backend.close_command(active_command_id) is never invoked. The server-side statement handle therefore leaks until the session (connection) is closed. This affects all three backends (Thrift, SEA, kernel) because the leak is in the shared Cursor.close() path, not backend-specific code. Each backend already implements a safe close_command (Thrift sends TCloseOperation, SEA sends DELETE/close, kernel no-ops on unknown ids).
Files:
src/databricks/sql/client.py,tests/e2e/test_driver.pyPlanned coverage:
Files changed
tests/e2e/test_driver.pysrc/databricks/sql/client.pytests/unit/test_client.pyTest plan
tests/e2e/test_driver.py::TestPySQLAsyncQueriesSuite::test_close_frees_async_handle_without_fetch— fails (red) against the original code, passes (green) after the fixtests/unit/test_client.py::ClientTestSuite::test_close_frees_async_command_without_result_set— fails (red) against the original code, passes (green) after the fixtests/unit/test_client.py::ClientTestSuite::test_close_swallows_close_command_errors— fails (red) against the original code, passes (green) after the fix🤖 Generated by engineer-bot (bug-fix flow) — review before merge.