]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
fix(pool): check connections' max_lifetime on ``check()``
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Thu, 8 Jun 2023 13:56:22 +0000 (15:56 +0200)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Tue, 13 Jun 2023 11:27:46 +0000 (13:27 +0200)
Close #482.

docs/news_pool.rst
psycopg_pool/psycopg_pool/pool.py
psycopg_pool/psycopg_pool/pool_async.py
tests/pool/test_pool.py
tests/pool/test_pool_async.py

index 66a9a8e0b6d8104130b6a0b1c85e6b637e57ad4d..6da2453eea4d8aff23694d61233d3f591b3f598f 100644 (file)
@@ -17,6 +17,13 @@ psycopg_pool 3.2.0 (unreleased)
   (:ticket:`#520`).
 
 
+psycopg_pool 3.1.8 (unreleased)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Enforce connections' ``max_lifetime`` on `~ConnectionPool.check()`
+  (:ticket:`#482`).
+
+
 Current release
 ---------------
 
index 67447cac57c6256660fc228f1b05b21cdfc9febc..023f071646af4ad3aee672a3e556fd022fa398f3 100644 (file)
@@ -437,6 +437,15 @@ class ConnectionPool(BasePool[Connection[Any]]):
 
         while conns:
             conn = conns.pop()
+
+            # Check for expired connections
+            if conn._expire_at <= monotonic():
+                logger.info("discarding expired connection %s", conn)
+                conn.close()
+                self.run_task(AddConnection(self))
+                continue
+
+            # Check for broken connections
             try:
                 conn.execute("SELECT 1")
                 if conn.pgconn.transaction_status == TransactionStatus.INTRANS:
index 01fdf63178d316eda5922bd23c2157d18f0167da..84e90e46dd6799619a99855006f2d1f6b3f8c3b3 100644 (file)
@@ -376,6 +376,15 @@ class AsyncConnectionPool(BasePool[AsyncConnection[Any]]):
 
         while conns:
             conn = conns.pop()
+
+            # Check for expired connections
+            if conn._expire_at <= monotonic():
+                logger.info("discarding expired connection %s", conn)
+                await conn.close()
+                self.run_task(AddConnection(self))
+                continue
+
+            # Check for broken connections
             try:
                 await conn.execute("SELECT 1")
                 if conn.pgconn.transaction_status == TransactionStatus.INTRANS:
index 29c4bf55456edfa93b9ec09e362cf4f02eef4ec7..af75fe61e3516c22c1aa615ea5e673919f6f5d5f 100644 (file)
@@ -1095,6 +1095,19 @@ def test_check_idle(dsn):
             assert conn.info.transaction_status == TransactionStatus.IDLE
 
 
+@pytest.mark.slow
+def test_check_max_lifetime(dsn):
+    with pool.ConnectionPool(dsn, min_size=1, max_lifetime=0.2) as p:
+        with p.connection() as conn:
+            pid = conn.info.backend_pid
+        with p.connection() as conn:
+            assert conn.info.backend_pid == pid
+        sleep(0.3)
+        p.check()
+        with p.connection() as conn:
+            assert conn.info.backend_pid != pid
+
+
 @pytest.mark.slow
 @pytest.mark.timing
 def test_stats_measures(dsn):
index 5a0169822da7f0a6c91f3a6a209cbc54e3d917cd..238843e23111eabf05a8d6b729685c832ee013c9 100644 (file)
@@ -1056,6 +1056,19 @@ async def test_check_idle(dsn):
             assert conn.info.transaction_status == TransactionStatus.IDLE
 
 
+@pytest.mark.slow
+async def test_check_max_lifetime(dsn):
+    async with pool.AsyncConnectionPool(dsn, min_size=1, max_lifetime=0.2) as p:
+        async with p.connection() as conn:
+            pid = conn.info.backend_pid
+        async with p.connection() as conn:
+            assert conn.info.backend_pid == pid
+        await asyncio.sleep(0.3)
+        await p.check()
+        async with p.connection() as conn:
+            assert conn.info.backend_pid != pid
+
+
 @pytest.mark.slow
 @pytest.mark.timing
 async def test_stats_measures(dsn):