-
Notifications
You must be signed in to change notification settings - Fork 148
Cursor.close() leaks server-side handle for async commands that were never fetched (#791) #873
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
e3658da
c7901ab
a480609
ee59c9c
244563d
dce9268
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -342,6 +342,50 @@ def test_execute_async__large_result(self, extra_params): | |
|
|
||
| assert len(result) == x_dimension * y_dimension | ||
|
|
||
| @pytest.mark.parametrize( | ||
| "extra_params", | ||
|
peco-review-bot[bot] marked this conversation as resolved.
|
||
| [ | ||
| {}, | ||
| { | ||
| "use_sea": True, | ||
| }, | ||
| ], | ||
| ) | ||
| def test_execute_async__close_without_fetch_frees_handle(self, extra_params): | ||
|
peco-review-bot[bot] marked this conversation as resolved.
|
||
| """Closing a cursor whose async command result was never fetched must free | ||
| the server-side statement handle (issue #791). Otherwise the handle leaks | ||
| until the session closes.""" | ||
| with self.cursor(extra_params) as cursor: | ||
| cursor.execute_async("SELECT 1") | ||
|
|
||
| # Capture the server-side command id before we close the cursor. | ||
| command_id = cursor.active_command_id | ||
| assert command_id is not None | ||
|
|
||
| backend = cursor.backend | ||
|
|
||
| # Sanity: the handle is live and pollable before close. | ||
| backend.get_query_state(command_id) | ||
|
|
||
| # User decides not to wait for the result and closes the cursor | ||
| # without ever calling get_async_execution_result(). | ||
| cursor.close() | ||
|
|
||
| # After close, the server-side handle must have been freed. How a | ||
| # re-poll of the saved command id surfaces that is backend-specific: | ||
| # - Thrift raises a server error on the closed handle. | ||
| # - SEA's get_query_state() does a plain GET and returns the | ||
| # status.state, so a freed statement may come back as a terminal | ||
| # CLOSED/CANCELLED state instead of raising. | ||
| # Accept either signal as proof the handle was freed. Pre-fix (leak), | ||
| # the poll instead returns a live/terminal-success state. | ||
| try: | ||
| state = backend.get_query_state(command_id) | ||
| except (RequestError, OperationalError, DatabaseError): | ||
| pass | ||
| else: | ||
| assert state in (CommandState.CLOSED, CommandState.CANCELLED) | ||
|
|
||
|
peco-review-bot[bot] marked this conversation as resolved.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔵 Low — The SEA branch of this test may be brittle. After
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The comment targets the SEA branch of an E2E test whose correct accepted-state set depends on what a live SEA warehouse actually returns from get_query_state() after close_command issues the statement DELETE. This job has no live-warehouse connection and must not run/add e2e tests, so I cannot verify SEA's real post-delete signal here. The reviewer's two options both hinge on that empirical fact: (a) confirm empirically — impossible in this job; (b) broaden the accepted states — unsafe to do blind, because the pre-fix leak "returns a live/terminal-success state," so broadening (e.g. accepting SUCCEEDED) without knowing SEA's freed-handle behavior would let the test pass in the leak case and destroy the regression it guards. A human needs to run this against a live SEA warehouse to observe the actual post-DELETE state (or 404), then either narrow the assertion to that confirmed signal or, if SEA gives no reliable freed signal, restructure the SEA branch (e.g. skip the re-poll assertion for SEA). Flagging for human judgment rather than guessing at a broadening that could mask the leak. |
||
|
|
||
| # Exclude Retry tests because they require specific setups, and LargeQueries too slow for core | ||
| # tests | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.