memory: Fix a leak in AsyncHTTPClient shutdown.
This fix is based on
https://github.com/tornadoweb/tornado/commit/8953e9beb1e376d9d907c77e61e0e628245de35d
Change-Id: Ic7b3b19204c72741600872c4391f05ff23a94163
diff --git a/tornado/httpclient.py b/tornado/httpclient.py
index a4a3728..6ad591b 100644
--- a/tornado/httpclient.py
+++ b/tornado/httpclient.py
@@ -142,8 +142,12 @@
impl = AsyncHTTPClient._impl_class
else:
impl = cls
- if io_loop in impl._async_clients() and not force_instance:
- return impl._async_clients()[io_loop]
+ if force_instance:
+ instance_cache = None
+ else:
+ instance_cache = impl._async_clients()
+ if instance_cache is not None and io_loop in instance_cache:
+ return instance_cache[io_loop]
else:
instance = super(AsyncHTTPClient, cls).__new__(impl)
args = {}
@@ -157,8 +161,13 @@
elif "max_clients" not in args:
args["max_clients"] = AsyncHTTPClient._DEFAULT_MAX_CLIENTS
instance.initialize(io_loop, **args)
- if not force_instance:
- impl._async_clients()[io_loop] = instance
+ # Make sure the instance knows which cache to remove itself from.
+ # It can't simply call _async_clients() because we may be in
+ # __new__(AsyncHTTPClient) but instance.__class__ may be
+ # SimpleAsyncHTTPClient.
+ instance._instance_cache = instance_cache
+ if instance_cache is not None:
+ instance_cache[instance.io_loop] = instance
return instance
def close(self):
@@ -167,8 +176,10 @@
create and destroy http clients. No other methods may be called
on the AsyncHTTPClient after close().
"""
- if self._async_clients().get(self.io_loop) is self:
- del self._async_clients()[self.io_loop]
+ if self._instance_cache is not None:
+ if self._instance_cache.get(self.io_loop) is not self:
+ raise RuntimeError("inconsistent AsyncHTTPClient cache")
+ del self._instance_cache[self.io_loop]
def fetch(self, request, callback, **kwargs):
"""Executes a request, calling callback with an `HTTPResponse`.