Skip to content

Connection pooling disable function hangs indefinitely #267

@bewithgaurav

Description

@bewithgaurav

Describe the bug

Connection pooling hangs indefinitely when pooling(enabled=False) is called after any connection has been created from the pool.

The pooling(enabled=False) function causes an infinite hang regardless of whether connections are still open or have been properly closed. This affects both individual scripts and the test suite, making it impossible to disable pooling cleanly.

Root Cause: The PoolingManager.disable() method only sets an internal flag but never actually calls the underlying C++ close_pooling() function to clean up connection pools. This leaves active connection pools with their mutexes and threads running, causing a deadlock during program termination.

To reproduce

from mssql_python import connect, pooling
import os

# Set your connection string
conn_str = "Driver={ODBC Driver 18 for SQL Server};Server=localhost,1433;Database=master;UID=sa;Pwd=YourPassword;Encrypt=no;TrustServerCertificate=yes;"

# This sequence ALWAYS hangs:
print("1. Enabling pooling...")
pooling(enabled=True)           # ✅ Works fine

print("2. Creating connection...")
conn = connect(conn_str)        # ✅ Works fine  

print("3. Closing connection...")
conn.close()                    # ✅ Works fine (optional - hang occurs even without this)

print("4. Disabling pooling...")
pooling(enabled=False)          # ❌ HANGS FOREVER - never returns

print("This line is never reached")

What works (no hang):

  • pooling(enabled=True) alone
  • pooling(enabled=False) alone
  • pooling(enabled=True) followed immediately by pooling(enabled=False) (no connections created)

What hangs:

  • pooling(enabled=False) after ANY connection has been created from the pool
  • Happens regardless of whether connections are closed or left open
  • Happens in test suites, causing them to hang indefinitely

Expected behavior

pooling(enabled=False) should:

  1. Immediately clean up all active connection pools
  2. Terminate background threads and release resources
  3. Return control to the caller without hanging
  4. Allow the program to exit normally

Further technical details

Python version: 3.13.3
SQL Server version: SQL Server (Docker container with Microsoft ODBC Driver 18)
Operating system: macOS 14.7.1 (also affects Linux)

Impact:

  • Makes it impossible to disable pooling in production code
  • Causes test suites to hang when they try to clean up pooling
  • Requires manual process termination (Ctrl+C)
  • Affects any code that needs to toggle pooling on/off

Technical Details:

  • Issue is in pooling.py in the PoolingManager.disable() method
  • The method sets _enabled = False but never calls ddbc_bindings.close_pooling()
  • The atexit.register(shutdown_pooling) checks is_enabled() which returns False, so cleanup never happens
  • Connection pools remain alive with active mutexes, causing deadlock during termination

Additional context

This bug makes pooling effectively unusable in any scenario where you need to disable it programmatically. It particularly affects:

  1. Test Suites: Tests that enable pooling cause subsequent tests to hang when trying to clean up
  2. Production Applications: Cannot safely disable pooling during runtime
  3. Development/Debugging: Cannot toggle pooling on/off for performance testing

The bug appears to be a design flaw in the pooling disable mechanism rather than a race condition or platform-specific issue.


Proposed Fix:
The fix involves modifying PoolingManager.disable() to actually call ddbc_bindings.close_pooling() when disabling pooling, rather than just setting a flag. Additional safety checks should prevent double-cleanup scenarios.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingtriage doneIssues that are triaged by dev team and are in investigation.

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions