Skip to content

Commit eb6c632

Browse files
committed
Allow tracking/reporting and closing of "lost" connections.
ConnectionPool keeps a WeakSet of in_use connections, allowing lost ones to be collected. Collection produces a warning and closes the underlying transport.
1 parent 5391c5f commit eb6c632

File tree

2 files changed

+21
-1
lines changed

2 files changed

+21
-1
lines changed

redis/asyncio/client.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,7 @@ def __del__(
546546
_grl().call_exception_handler(context)
547547
except RuntimeError:
548548
pass
549+
self.connection._close()
549550

550551
async def aclose(self, close_connection_pool: Optional[bool] = None) -> None:
551552
"""

redis/asyncio/connection.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import socket
66
import ssl
77
import sys
8+
import warnings
89
import weakref
910
from abc import abstractmethod
1011
from itertools import chain
@@ -204,6 +205,24 @@ def __init__(
204205
raise ConnectionError("protocol must be either 2 or 3")
205206
self.protocol = protocol
206207

208+
def __del__(self, _warnings: Any = warnings):
209+
# For some reason, the individual streams don't get properly garbage
210+
# collected and therefore produce no resource warnings. We add one
211+
# here, in the same style as those from the stdlib.
212+
if self._writer:
213+
_warnings.warn(
214+
f"unclosed Connection {self!r}", ResourceWarning, source=self
215+
)
216+
self._close()
217+
218+
def _close(self):
219+
"""
220+
Internal method to silently close the connection without waiting
221+
"""
222+
if self._writer:
223+
self._writer.close()
224+
self._writer = self._reader = None
225+
207226
def __repr__(self):
208227
repr_args = ",".join((f"{k}={v}" for k, v in self.repr_pieces()))
209228
return f"{self.__class__.__name__}<{repr_args}>"
@@ -1017,7 +1036,7 @@ def __repr__(self):
10171036

10181037
def reset(self):
10191038
self._available_connections = []
1020-
self._in_use_connections = set()
1039+
self._in_use_connections = weakref.WeakSet()
10211040

10221041
def can_get_connection(self) -> bool:
10231042
"""Return True if a connection can be retrieved from the pool."""

0 commit comments

Comments
 (0)