From: Daniele Varrazzo Date: Wed, 13 Nov 2024 13:19:12 +0000 (+0100) Subject: fix(pool): print a warning if gather times out on del X-Git-Tag: 3.2.4~24 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4fad08703b88804216a3c4e3cdd0e0199a3daa63;p=thirdparty%2Fpsycopg.git fix(pool): print a warning if gather times out on del In Python 3.13 something changed on interpreter shutdown and now stopping threads on __del__ fails. See #930, #954. --- diff --git a/docs/news_pool.rst b/docs/news_pool.rst index 405631681..f6f830945 100644 --- a/docs/news_pool.rst +++ b/docs/news_pool.rst @@ -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 --------------- diff --git a/psycopg_pool/psycopg_pool/_acompat.py b/psycopg_pool/psycopg_pool/_acompat.py index d58548515..9081d3ecd 100644 --- a/psycopg_pool/psycopg_pool/_acompat.py +++ b/psycopg_pool/psycopg_pool/_acompat.py @@ -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]: diff --git a/psycopg_pool/psycopg_pool/pool.py b/psycopg_pool/psycopg_pool/pool.py index 96d81b9a8..3696a83ab 100644 --- a/psycopg_pool/psycopg_pool/pool.py +++ b/psycopg_pool/psycopg_pool/pool.py @@ -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() diff --git a/psycopg_pool/psycopg_pool/pool_async.py b/psycopg_pool/psycopg_pool/pool_async.py index 48147bdf5..718cb9c25 100644 --- a/psycopg_pool/psycopg_pool/pool_async.py +++ b/psycopg_pool/psycopg_pool/pool_async.py @@ -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()