88import asyncio
99import functools
1010import inspect
11+ import logging
1112import time
1213import warnings
1314
1617from . import exceptions
1718
1819
20+ logger = logging .getLogger (__name__ )
21+
22+
1923class PoolConnectionProxyMeta (type ):
2024
2125 def __new__ (mcls , name , bases , dct , * , wrap = False ):
@@ -621,7 +625,10 @@ async def close(self):
621625 Wait until all pool connections are released, close them and
622626 shut down the pool. If any error (including cancellation) occurs
623627 in ``close()`` the pool will terminate by calling
624- :meth:'Pool.terminate() <pool.Pool.terminate>`.
628+ :meth:`Pool.terminate() <pool.Pool.terminate>`.
629+
630+ It is advisable to use :func:`python:asyncio.wait_for` to set
631+ a timeout.
625632
626633 .. versionchanged:: 0.16.0
627634 ``close()`` now waits until all pool connections are released
@@ -635,6 +642,9 @@ async def close(self):
635642 self ._closing = True
636643
637644 try :
645+ warning_callback = self ._loop .call_later (
646+ 60 , self ._warn_on_long_close )
647+
638648 release_coros = [
639649 ch .wait_until_released () for ch in self ._holders ]
640650 await asyncio .gather (* release_coros , loop = self ._loop )
@@ -648,9 +658,16 @@ async def close(self):
648658 raise
649659
650660 finally :
661+ warning_callback .cancel ()
651662 self ._closed = True
652663 self ._closing = False
653664
665+ def _warn_on_long_close (self ):
666+ logger .warning ('Pool.close() is taking over 60 seconds to complete. '
667+ 'Check if you have any unreleased connections left. '
668+ 'Use asyncio.wait_for() to set a timeout for '
669+ 'Pool.close().' )
670+
654671 def terminate (self ):
655672 """Terminate all connections in the pool."""
656673 if self ._closed :
0 commit comments