Skip to content

Commit 4df05c7

Browse files
fix: make pool initialize() idempotent to prevent double init
The pattern `async with await create_pool(...)` called initialize() twice (once in create_pool, once in __aenter__), creating 2x min_size connections. Now guarded by an _initialized flag. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 0932405 commit 4df05c7

2 files changed

Lines changed: 28 additions & 0 deletions

File tree

src/dqliteclient/pool.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,13 @@ def __init__(
4444
self._size = 0
4545
self._lock = asyncio.Lock()
4646
self._closed = False
47+
self._initialized = False
4748

4849
async def initialize(self) -> None:
4950
"""Initialize the pool with minimum connections."""
51+
if self._initialized:
52+
return
53+
self._initialized = True
5054
for _ in range(self._min_size):
5155
conn = await self._create_connection()
5256
await self._pool.put(conn)

tests/test_pool.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,30 @@ async def test_acquire_when_closed(self) -> None:
3232
async with pool.acquire():
3333
pass
3434

35+
async def test_double_initialize_is_idempotent(self) -> None:
36+
"""Calling initialize() twice should not create double connections."""
37+
pool = ConnectionPool(["localhost:9001"], min_size=2, max_size=5)
38+
39+
mock_conn = MagicMock()
40+
mock_conn.is_connected = True
41+
mock_conn.connect = AsyncMock()
42+
mock_conn.close = AsyncMock()
43+
44+
create_count = 0
45+
46+
async def mock_connect(**kwargs):
47+
nonlocal create_count
48+
create_count += 1
49+
return mock_conn
50+
51+
with patch.object(pool._cluster, "connect", side_effect=mock_connect):
52+
await pool.initialize()
53+
await pool.initialize() # Second call should be no-op
54+
55+
assert create_count == 2 # Only 2 (min_size), not 4
56+
57+
await pool.close()
58+
3559
async def test_cancellation_does_not_leak_connection(self) -> None:
3660
"""Cancelling a task that holds a connection should clean it up."""
3761
import asyncio

0 commit comments

Comments
 (0)