]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
fix(pool): print a warning if gather times out on del
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Wed, 13 Nov 2024 13:19:12 +0000 (14:19 +0100)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Thu, 14 Nov 2024 09:29:12 +0000 (10:29 +0100)
In Python 3.13 something changed on interpreter shutdown and now
stopping threads on __del__ fails.

See #930, #954.

docs/news_pool.rst
psycopg_pool/psycopg_pool/_acompat.py
psycopg_pool/psycopg_pool/pool.py
psycopg_pool/psycopg_pool/pool_async.py

index f5c4ff973e0e2ffc17f956e61c14808b10864fa8..eacba27d52dc9b36c250ce93e94542d56f0ff38e 100644 (file)
@@ -7,6 +7,17 @@
 ``psycopg_pool`` release notes
 ==============================
 
+Future releases
+---------------
+
+psycopg_pool 3.2.4
+^^^^^^^^^^^^^^^^^^
+
+- Add a hint to the warning printed if threads fail to stop during
+  ``__del__``, which has been reported happening during interpreter shutdown
+  on Python 3.13 (see #954).
+
+
 Current release
 ---------------
 
index d58548515bc2a649eb148b4f04fa5528800ce9ef..9081d3ecd8647ae22503f942d52a15a8e45adb45 100644 (file)
@@ -130,7 +130,9 @@ def spawn(
     return t
 
 
-async def agather(*tasks: asyncio.Task[Any], timeout: float | None = None) -> None:
+async def agather(
+    *tasks: asyncio.Task[Any], timeout: float | None = None, timeout_hint: str = ""
+) -> None:
     """
     Equivalent to asyncio.gather or Thread.join()
     """
@@ -149,9 +151,13 @@ async def agather(*tasks: asyncio.Task[Any], timeout: float | None = None) -> No
         if t.done():
             continue
         logger.warning("couldn't stop task %r within %s seconds", t.get_name(), timeout)
+        if timeout_hint:
+            logger.warning("hint: %s", timeout_hint)
 
 
-def gather(*tasks: threading.Thread, timeout: float | None = None) -> None:
+def gather(
+    *tasks: threading.Thread, timeout: float | None = None, timeout_hint: str = ""
+) -> None:
     """
     Equivalent to asyncio.gather or Thread.join()
     """
@@ -162,6 +168,8 @@ def gather(*tasks: threading.Thread, timeout: float | None = None) -> None:
         if not t.is_alive():
             continue
         logger.warning("couldn't stop thread %r within %s seconds", t.name, timeout)
+        if timeout_hint:
+            logger.warning("hint: %s", timeout_hint)
 
 
 def asleep(seconds: float) -> Coroutine[Any, Any, None]:
index 4a086827c0b7959cc8abb72d710be18cc3c343e3..e93440e214baafe055189bd7ac649d1a1ec94329 100644 (file)
@@ -107,7 +107,8 @@ class ConnectionPool(Generic[CT], BasePool):
             return
 
         workers = self._signal_stop_worker()
-        gather(*workers, timeout=5.0)
+        hint = "you can try to call 'close()' explicitly or to use the pool as context manager"
+        gather(*workers, timeout=5.0, timeout_hint=hint)
 
     def _check_open_getconn(self) -> None:
         super()._check_open_getconn()
index ac6925aed76ad95d35eb0740303992f4f4ca4fa4..08b39477e992b61b0b9a950da3fe0c9abea96cd5 100644 (file)
@@ -112,7 +112,11 @@ class AsyncConnectionPool(Generic[ACT], BasePool):
                 return
 
             workers = self._signal_stop_worker()
-            agather(*workers, timeout=5.0)
+            hint = (
+                "you can try to call 'close()' explicitly "
+                "or to use the pool as context manager"
+            )
+            agather(*workers, timeout=5.0, timeout_hint=hint)
 
     def _check_open_getconn(self) -> None:
         super()._check_open_getconn()