Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

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

Đang mở
#746 1 bình luận 0 reaction 1 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 2 ngày

@bewithgaurav đang làm issue này rồi.

Từ ngày 21/9/2026.

  • #797 của @rksharma-owg — đang mở

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
62/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
cpp, python
Lĩnh vực
backend, databases

Hướng nghiên cứu

Đọc mssql_python/pybind/connection/connection_pool.cpp, tập trung vào phần bắt lỗi ở Phase 3 của ConnectionPool::acquire, closePools() và ConnectionPool::close. Truy vết các luồng reservation và cleanup, sau đó kiểm tra PR #678 đã thay đổi việc khởi tạo Connection như thế nào. Hoàn tất khi một regression test bao phủ việc đan xen giữa lỗi và vô hiệu hóa, đồng thời số lượng kết nối vật lý đang hoạt động không bao giờ vượt quá max_size.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

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.

Ngôn ngữ chính
Python
Star
478
Fork
62
Merge trung bình
3 ngày 19 phút
Pull request đã merge (30 ngày)
28

Chuẩn bị môi trường

Mở trong Codespaces

Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của microsoft/mssql-python

Tất cả issue của microsoft/mssql-python

Issue tương tự

Thêm issue về Python

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.