]> 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:26:38 +0000 (13:26 +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 8d4ec4567ec041a7e703a3b3dfb10b900de1c9ca..2f94544e4897ebde1ea4d04a8ec0828d2cedbec9 100644 (file)
@@ -7,6 +7,16 @@
 ``psycopg_pool`` release notes
 ==============================
 
+Future releases
+---------------
+
+psycopg_pool 3.1.8 (unreleased)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Enforce connections' ``max_lifetime`` on `~ConnectionPool.check()`
+  (:ticket:`#482`).
+
+
 Current release
 ---------------
 
index 498ef7020f8521a6c07807460863263c54cfe248..1a1a85266c3edefd3a2a5937cce4c66a1a5f1389 100644 (file)
@@ -432,6 +432,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 74a30dd2835b97a2ca43c5453fcad2a88ddef8e1..27c5dcba22b2dcc6e2e6cd9933863fd0d061a00a 100644 (file)
@@ -370,6 +370,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 83faf18dad2584d75eae3daa5bc6a94937c4a87c..df1348a35eb2641d061c4e6083b9fafc0595f65e 100644 (file)
@@ -1046,6 +1046,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):