]> 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>
Fri, 15 Nov 2024 10:05:57 +0000 (11:05 +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 40563168192e8e8bfd7203090049c3b1cf57b0cd..f6f8309453e160333f7704b86068ec93d86c746d 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 96d81b9a8114c7ce8891b1a3d0d416994ee1f44a..3696a83ab2dfc9b74601b9d7c8ed60a878f1ead0 100644 (file)
@@ -106,7 +106,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 48147bdf54203431d4df9b55402d7ffba93e0ec9..718cb9c256c403d7903772bc6aa06803007ff9d5 100644 (file)
@@ -111,7 +111,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()