Skip to content

Do not leak query pool capacity on cancelled session create - #872

Open
vgvoleg wants to merge 2 commits into
mainfrom
fix-query-pool-cancelled-create-leak
Open

Do not leak query pool capacity on cancelled session create#872
vgvoleg wants to merge 2 commits into
mainfrom
fix-query-pool-cancelled-create-leak

Conversation

@vgvoleg

@vgvoleg vgvoleg commented Aug 6, 2026

Copy link
Copy Markdown
Member

Fixes #870.

asyncio.CancelledError derives from BaseException, so the except Exception rollback in async QuerySessionPool.acquire() never ran when a task was cancelled inside _create_new_session(). _current_size stayed incremented and the slot was lost for good; once the counter reached size, every acquire() blocked on _queue.get() forever.

Added an except BaseException branch that restores the counter. Also widened the _attach() guard (sync and async) from Exception to BaseException, so a cancelled/interrupted attach closes the session and cancels the stream instead of orphaning it server-side.

asyncio.CancelledError is not an Exception, so cancelling acquire() while
_create_new_session() was in flight left _current_size incremented forever
and permanently lost a pool slot. Also close the session when attach is
cancelled or interrupted, instead of orphaning it server-side.

Fixes #870
@codecov

codecov Bot commented Aug 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.37%. Comparing base (53b1b16) to head (8a4fd0f).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #872      +/-   ##
==========================================
+ Coverage   82.33%   82.37%   +0.03%     
==========================================
  Files          99       99              
  Lines       12749    12752       +3     
  Branches     1242     1242              
==========================================
+ Hits        10497    10504       +7     
+ Misses       1797     1794       -3     
+ Partials      455      454       -1     
Flag Coverage Δ
integration 80.23% <61.53%> (+0.02%) ⬆️
unit 48.55% <100.00%> (+0.18%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
ydb/aio/query/pool.py 94.73% <100.00%> (+0.10%) ⬆️
ydb/aio/query/session.py 92.50% <100.00%> (+3.75%) ⬆️
ydb/query/session.py 91.83% <100.00%> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes an async QuerySessionPool.acquire() cancellation edge case where pool capacity could be leaked permanently, eventually causing all subsequent acquires to block forever. The PR also hardens both sync and async session attach paths so interrupted/cancelled attach attempts properly tear down the stream and invalidate the session to avoid server-side orphans.

Changes:

  • Add except BaseException rollback in async QuerySessionPool.acquire() to restore _current_size on cancellation/interruption during session creation.
  • Broaden _attach() guards (sync and async) from Exception to BaseException to ensure interrupted attach always closes/invalidates the session and cancels the stream.
  • Add regression tests covering acquire-cancellation capacity leaks and attach interruption/cancellation teardown, plus a user-facing changelog entry.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
ydb/aio/query/pool.py Roll back _current_size on BaseException during session creation to prevent leaked pool capacity.
ydb/aio/query/pool_test.py Add async regression tests for cancelled create/acquire and cancelled attach behavior.
ydb/aio/query/session.py Ensure cancelled/interrupting attach invalidates session and tears down attach stream.
ydb/query/session.py Ensure interrupted attach invalidates session and tears down attach stream.
ydb/query/pool_test.py Add sync regression tests for interrupted attach teardown behavior.
CHANGELOG.md Document the user-visible fix for async pool cancellation capacity leaks and attach teardown.
Suppressed comments (2)

ydb/aio/query/pool_test.py:202

  • This await entered.wait() has no timeout, so a regression could cause the test run to hang indefinitely. Prefer asyncio.wait_for with a bounded timeout to fail fast.
            await entered.wait()

ydb/aio/query/pool_test.py:221

  • This await entered.wait() has no timeout, so if the attach call never signals the event the test can hang indefinitely. Wrap it in asyncio.wait_for to bound the wait.
            await entered.wait()

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ydb/aio/query/pool.py
Comment on lines 140 to +144
# TODO: this exception could be retried via retrier, so no need to log error here. Probably we should retry this right in create_new_session method.
logger.warning("Failed to create new session")
self._current_size -= 1
raise e
except BaseException:
Comment thread ydb/aio/query/pool_test.py Outdated
pool._create_new_session = self._hanging_create(entered)

task = asyncio.create_task(pool.acquire())
await entered.wait()
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.

bug: QuerySessionPool.acquire() permanently leaks pool capacity when cancelled during session creation

2 participants