-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Connection not closed when request is cancelled #253
Comments
try to add "yield from r.release()" after this line "r = yield from request('get', 'http://yahoo.com', connector=connector)" |
here is proper make_request() function:
|
Same thing. |
Cannot reproduce the issue. Well, actually I can create connections leak by using high request rate when connections are opens much faster than OS is able to clean them. Using P.S. aiohttp 0.14.1 |
Ok, I'll see if I can make a new gist that can reproduce it, that resembles my setup more closely. |
Ok, here's a gist that more closely reproduces my problem, using this code, I can reproduce it every time: It creates an origin server and a proxy server. The proxy server will create many connections to the origin server. When it blows up, sockets are left open. I hammer the proxy server like so:
Thanks a lot for trying to help me, I really appreciate it! |
i think this is related keep-alive, by default TCPConnector uses keepalive_timeout=30, try to reduce it to 1 |
I'm callilng response.read() first and then response.release(). Just tried keepalive_timeout=1, same result though. It cleans up some sockets, but not all of them. |
if keepalive_timeout helps then it is different problem. you open too many connections, aiohttp does not release connections fast enough. you may need to write custom TCPConnector that opens only limited number of connections, or you can recycle TCPConnector after some amount of processed requests. |
No, that's not it. Once the connection between the client (apachebench in this case) and the aiohttp server is lost, the aiohttp server will cancel the current request (throws a CancelledError in the handle_request coroutine), which causes the BaseConnector to lose references to some Connection objects. The underlying sockets of those Connection objects are never closed. I have a fix for that exact case. So if you have a look, you'll see how this can happen: nbraem@73016c4 This is not so far fetched, because connections to an aiohttp server can break and the server might also create a lot of connections itself, e.g. to a database or to a cache. You are totally right that TCPConnector should have a configurable maximum of open connections per host, which would also solve my problem. I was planning on also doing that. I think it would be a great addition to aiohttp, because of the database connection use case. |
i'm not sure why removing this line "self._conns.pop(key, None)" helps. |
I have a second commit in the pull request which is better: nbraem@5dd86d0 In the case I'm describing, self._conns[key] will contain an array of hundreds of open connections to the same host. But if one of them satisfies this condition:
Then the entire array of connections is popped, and the cleanup task will never be able to close the sockets (transports) when the keepalive_timeout hits. So you've lost the reference to the sockets, and they're never closed. |
Ok, that's better On Thursday, January 22, 2015, Nicolas Braem [email protected]
|
Grr. I would like to have at lease one unittest for any bugfix, especially for very subtle one as the issue. I've done it in d5e4d6a but please keep our test suite strict. |
Issues aio-libs#253 and aio-libs#254 implemented a `_conns` key evince logic in the function that actually **adds** items to `_conns` Issue aio-libs#406 tweaked this logic even more, making early and eviction of reusable items in the pool possible. Here we put the key eviction logic where it belongs: in the method that **removes** items from the `_conns` pool.
Issues #253 and #254 implemented a `_conns` key evince logic in the function that actually **adds** items to `_conns` Issue #406 tweaked this logic even more, making early and eviction of reusable items in the pool possible. Here we put the key eviction logic where it belongs: in the method that **removes** items from the `_conns` pool.
When making a lot of concurrent client requests to the same host using connection pooling, TCPConnector will create a lot of connections. When cancelling these client requests, not all connections are closed.
This is not easy to reproduce. I have a long running server process, and I can see the open sockets increasing over time.
Here's a gist that reproduces the conditions. When the code prints DONE, leave the process running and look at the open sockets (e.g. lsof -p | grep http). After the keepalive_timeout of 30 seconds, most connections are closed, but occasionally (1 in 5 runs for me), there is a dangling socket. You may need to change the sleep timeout for cancellation depending on how fast your connection is:
https://gist.github.com/nbraem/0e5178288ffd94372062
I have a fix, I'll send a pull request shortly.
The text was updated successfully, but these errors were encountered: