Release session in close() even if rollback fails - #43
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The new regression test monkeypatches internal methods without restoring them, which can cause cascading fixture-teardown failures and make test failures flaky/harder to diagnose.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Pull request overview
This PR fixes a resource-leak scenario in the YDB DB-API connection teardown path: if rollback() raises (e.g., due to an invalidated session), close() now still releases the checked-out session back to the pool and performs owned pool/driver shutdown, for both sync and async connections.
Changes:
- Update
Connection.close()andAsyncConnection.close()to perform session release,_tx_contextreset, and owned pool/driver shutdown in afinallyblock even whenrollback()raises. - Add a regression test that forces
tx_context.rollback()to raiseBadSessionand asserts thatclose()still releases the session and clears connection state (sync + async variants).
File summaries
| File | Description |
|---|---|
ydb_dbapi/connections.py |
Ensures close() always performs cleanup (release/reset/stop) via try/finally in both sync and async connections. |
tests/test_connections.py |
Adds a regression test covering the “rollback raises but close still releases session” scenario for both sync and async connections. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
| released = [] | ||
| original_release = connection._session_pool.release | ||
|
|
||
| def release(session: ydb.QuerySession) -> any: | ||
| released.append(session) | ||
| return original_release(session) | ||
|
|
||
| connection._session_pool.release = release | ||
|
|
||
| def failing_rollback(*args: any, **kwargs: any) -> None: | ||
| raise ydb.issues.BadSession("session is invalidated") | ||
|
|
||
| connection._tx_context.rollback = failing_rollback | ||
|
|
||
| with pytest.raises(dbapi.Error): | ||
| maybe_await(connection.close()) | ||
|
|
Fixes #42
close()calledrollback()first and released the session only afterwards. Ifrollback()raised — the expected outcome when the session was invalidated mid-request — the release was skipped, the session was abandoned and its pool slot was lost permanently.Session release,
_tx_contextreset and owned pool/driver shutdown now happen in afinally, in bothConnectionandAsyncConnection. The rollback error is still propagated.Test:
begin(), forcetx_context.rollbackto raiseBadSession, assertclose()raises but still releases the session back to the pool.