Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

Connection pool can briefly exceed max_size when pooling is disabled under load

未关闭
#746 1 条评论 0 个 reaction 已指派 1 人 在 GitHub 查看

维护者通常 1 天内回复

@bewithgaurav 已经在做这个了。

开始于 2026年9月21日。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
62/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
技术栈
cpp, python
领域
backend, databases

调研方向

阅读 mssql_python/pybind/connection/connection_pool.cpp,重点关注 ConnectionPool::acquire 的 Phase 3 failure catch、closePools() 和 ConnectionPool::close。跟踪 reservation 和 cleanup 路径,然后检查 PR #678 如何更改了 Connection 的构造。完成的标准是:有一个 regression test 覆盖 failure/disable 交错场景,并且活动的物理连接数永远不超过 max_size。

由索引模型根据 Issue 内容生成。

描述

area: connectivity-auth bug triage done under development
Describe the bug

The connection pool can transiently exceed its configured max_size when pooling is disabled (or the process begins shutting down) while new physical connections are being opened concurrently. The pool's internal reserved-capacity counter (_current_size) can drift below the true number of live connections, after which the pool opens more physical connections than max_size allows. It is transient and self-corrects as connections close.

Root cause: _current_size is a bare counter with no record of which reservation a given decrement belongs to. The failed-open cleanup runs if (_current_size > 0) --_current_size, while a pool disable/close runs _current_size = 0. If a reset lands between a thread reserving a slot and that same thread's open failing, the thread's decrement cancels a different thread's live reservation instead of its own.

Exception message: none. This is a silent _current_size accounting drift, no exception or stack trace.
To reproduce

This is a rare timing race, so it is not deterministically reproducible from a plain script. It requires a new connection to fail to open at the exact moment pooling is disabled or the process is shutting down. The interleave that produces it, with max_size = 2:

import mssql_python
from concurrent.futures import ThreadPoolExecutor

mssql_python.pooling(max_size=2)

# 1. Thread A calls connect(), reserves a slot -> _current_size = 1,
#    then starts opening a new physical connection (outside the pool lock).
# 2. Another thread disables pooling: closePools() sets _current_size = 0.
# 3. Thread B calls connect(), reserves the freed slot -> _current_size = 1.
# 4. Thread A's open fails (handle alloc / network error): its cleanup runs
#    --_current_size -> 0, cancelling B's slot instead of A's.
# 5. Thread B's open succeeds, but _current_size now reads 0.
# 6. Further connect() calls see room and open past max_size.

Observable symptom while the count is drifted: more live sessions than the configured cap.

SELECT COUNT(*) FROM sys.dm_exec_sessions WHERE login_name = 'yourapp';
-- transiently returns 3 with max_size = 2
Expected behavior

The number of live physical connections should never exceed max_size, regardless of a connection-open failure racing a pooling disable or process shutdown.

Further technical details

Python version: any
SQL Server version: any
Operating system: any. The race is in the cross-platform C++ pool, not platform specific.

Additional context

Area: mssql_python/pybind/connection/connection_pool.cpp, the Phase 3 failure catch in ConnectionPool::acquire, plus closePools() and ConnectionPool::close.

Regression status: pre-existing for the connect()-failure path. PR #678 moved Connection construction out of _mutex (required to fix the #671 deadlock), which widens the same race to also cover constructor failures such as ODBC env init, handle allocation, and OOM. Raised during review of #678.

Proposed fix: give the pool a generation counter. close()/closePools() bumps it under the lock, a reserver snapshots it at ++_current_size, and the failure cleanup only decrements if the generation still matches. This makes the decrement attributable and closes both the constructor and connect paths. Roughly 6 to 8 lines plus a regression test that forces the interleave.

主要语言
Python
星标
478
派生
62
平均合并
3 天 1 小时
30 天内合并 PR
27

环境准备

在 Codespaces 中打开

在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

microsoft/mssql-python 的其他 Issue

查看 microsoft/mssql-python 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。