Pooled connection checkout has no timeout: connect() hangs ~16 min on a dead socket
Maintainer antworten meist innerhalb von 1 Tag
Bewertung
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Anfängerfreundlichkeit
- 48/100
Rechercherichtung
Start by tracing pooled connection checkout in the driver, especially isAlive() and reset(); the issue identifies SQL_ATTR_CONNECTION_DEAD and SQL_ATTR_TXN_ISOLATION as relevant. Reproduce with the provided Python script against SQL Server, then inspect how connection validation and login timeouts are applied. Done means pooled checkout is bounded or the behavior is documented, as the issue requests.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
Describe the bug
With pooling enabled, if a pooled connection's TCP socket has been silently dropped (no FIN/RST), the next connect() that reuses it blocks until the OS gives up on the socket. On Linux with the default net.ipv4.tcp_retries2=15 that is ~16 minutes. The login timeout doesn't apply. Once the socket errors, the pool opens a new connection and connect() returns successfully.
If several pooled connections are dead, one connect() checks them one after another.
From the source, isAlive() only reads the cached SQL_ATTR_CONNECTION_DEAD flag, so a dead socket passes it. reset() then sets SQL_ATTR_TXN_ISOLATION, which appears to be the call that waits on the server, with no timeout.
To reproduce
Client: python:3.12-slim-trixie container (linux/amd64), mssql-python==1.16.0, run with --cap-add NET_ADMIN. Server: mcr.microsoft.com/mssql/server:2022-latest, reachable as sqlserver.
import os, subprocess, time
import mssql_python
mssql_python.pooling(idle_timeout=600)
kw = dict(Server="sqlserver", UID=os.environ["DB_USER"], PWD=os.environ["DB_PASSWORD"], Encrypt="yes",
TrustServerCertificate="yes", timeout=15, autocommit=True)
conn = mssql_python.connect(**kw)
cur = conn.cursor()
cur.execute("select client_tcp_port from sys.dm_exec_connections where session_id = @@SPID")
port = cur.fetchone()[0]
conn.close() # back to the pool
# silently drop that connection's traffic (DROP, so no RST is sent)
subprocess.run(["iptables", "-A", "OUTPUT", "-p", "tcp", "--sport", str(port), "-j", "DROP"], check=True)
subprocess.run(["iptables", "-A", "INPUT", "-p", "tcp", "--dport", str(port), "-j", "DROP"], check=True)
time.sleep(8)
t = time.monotonic()
mssql_python.connect(**kw).close() # reuses the dead pooled connection
print(f"connect() took {time.monotonic() - t:.1f}s")
Results:
| Case | connect() duration |
|---|---|
tcp_retries2=15 (Linux default) |
951.8 s |
tcp_retries2=5 (--sysctl net.ipv4.tcp_retries2=5) |
~13 s |
3 dead pooled connections, tcp_retries2=5 |
29.5 s |
| Pooling disabled | 0.02 s |
The same happens on 1.15.0, and with autocommit=False. It doesn't happen if the socket was dead long enough for TCP keepalive to mark it dead first (~40 s with the default KeepAlive=30).
Expected behavior
Checking out a pooled connection should be bounded in time, for example by the login timeout or a separate validation timeout, with a timed-out candidate treated as dead. Alternatively, the checkout could avoid a server round trip. At minimum, the behaviour should be documented.
Further technical details
- Python version: 3.12.15
- mssql-python: 1.15.0 and 1.16.0
- SQL Server version: SQL Server 2022 (repro); also seen against Azure SQL Managed Instance
- Operating system: Debian 13 (trixie),
linux/amd64
Additional context
The investigation, repro and analysis were done with the help of Claude Opus 5.5. The results above were measured; the root-cause reading of the source is our interpretation and may be wrong.
- Vorherrschende Sprache
- Python
- Sterne
- 479
- Forks
- 62
- Ø Merge
- 2 T. 9 Std.
- Gemergte PRs (30 T.)
- 18
Entwicklungsumgebung
Startet den Dev-Container des Projekts im Browser, mit Ihrem eigenen GitHub-Konto.
- Kein Dockerfile und keine Docker-Compose-Datei
- Hat eine Pull-Request-Vorlage
- Beitragsleitfaden lesen
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus microsoft/mssql-python
-
bulkcopy_arrow() / bulkcopy()` broken in 1.16.0Evtl. vergeben @jahnvi480 hat das vor 1 Tag übernommen. Offenarea: bulk-copy bug inADO triage done under development
Schwierigkeit 3/5 Ein halber Tag Anfängerfreundlichkeit 72/100
microsoft/mssql-python#855 · 2 Kommentare · 1 zugewiesene Person ·
Maintainer antworten meist innerhalb von 1 Tag
-
triage needed
Schwierigkeit 5/5 Über eine Woche Anfängerfreundlichkeit 38/100
microsoft/mssql-python#850 · 2 Kommentare · 1 Reaktion ·
Maintainer antworten meist innerhalb von 1 Tag
-
bulkcopy() & bulkcopy_arrow() fail with Schannel AcquireCredentialsHandleW error 0x8009030D (SEC_E_UNKNOWN_CREDENTIALS)Evtl. vergeben @jahnvi480 hat das vor 3 Tagen übernommen. Offenarea: bulk-copy bug inADO triage done
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 20/100
microsoft/mssql-python#848 · 5 Kommentare · 1 zugewiesene Person ·
Maintainer antworten meist innerhalb von 1 Tag
-
macOS: encrypted connections fail after Homebrew moved the `openssl` alias to `openssl@4`Evtl. vergeben @bewithgaurav hat das vor 23 Tagen übernommen. Offenarea: packaging-platform bug triage needed
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 55/100
microsoft/mssql-python#826 · 2 Kommentare · 3 Reaktionen · 1 zugewiesene Person ·
Maintainer antworten meist innerhalb von 1 Tag
-
Announcement: mssql-python is coming to Django through mssql-django 2.0Evtl. wieder frei @bewithgaurav hat das vor 49 Tagen übernommen, und es ist kein Pull Request offen. Offenannouncement
microsoft/mssql-python#748 · 1 zugewiesene Person ·
Maintainer antworten meist innerhalb von 1 Tag
Alle Issues in microsoft/mssql-python
Ähnliche Issues
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 67/100
MISP/misp-workbench#496 ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 66/100
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 1/5 1-3 Stunden Anfängerfreundlichkeit 88/100
fossasia/visdom-dev#69 ·
Maintainer antworten meist innerhalb von 3 Tagen
-
[Bug] Parameters named like a property break to_xcal()Evtl. vergeben @atharvasalunke1267 hat das heute übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 65/100
collective/icalendar#2018 · 2 Kommentare ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 75/100
Maintainer antworten meist innerhalb von 1 Tag