-
-
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
Make concurrent connections respect limits #581
Conversation
# The limit defines the maximum number of concurrent connections | ||
# for a key. Waiters must be counted against the limit, even before | ||
# the underlying connection is created. | ||
available = limit - len(waiters) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect you should respect self._acquired
too.
@asvetlov I updated the check for available connections based on your feedback. My original test didn't catch the problem because I was only checking the case where all connections were requested up front. I've now updated it to make more than Sorry it took me a while to get back to this. I had prepared the changes, but then our new baby decided it was time to arrive. I got a little distracted for a few days. :-) |
I wish happy long life for your baby. |
available = limit - len(waiters) - len(self._acquired[key]) | ||
|
||
# Don't wait if there are connections available. | ||
if available > 0: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make short-circuit here?
If no available connections then create future and wait for it, pass the next lines otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nevermind.
Thanks a lot! |
When I tried to use
aiohttp.ClientSession
to make many concurrent requests to the same server, I found that I ended up with more connections than I expected.Using the current master branch, the script below makes 3 connections for 3 requests, despite setting a limit of 1 on the connector. The problem seems to be that connections aren't counted against the limit until after the underlying trasport has been created. This creates a race condition where
connect
yields from_create_connection
before recording anywhere that one of the available connections has been consumed. Subsequent calls toconnect
that begin before the earlier_create_connnection
call has returned are able to create an unlimited number of connections.This pull request includes a new test that fails on the current master branch, but passes with my changes to the connector. I'm also including the first version of the test that I wrote below, because I was surprised when it actually passed on current master. I want to highlight the use of a mock that returns a done future in place of a coroutine, in this case
_create_connection
. I copied this pattern fromtest_connect_with_limit
and it broke my test because while a function that returns a done future can be yielded from as if it were a coroutine, it never actually yields control back to the event loop. The result in this case was that all tasks ran sequentially rather than concurrently as they would in real use. I replaced the mock with a real coroutine and the test failed as expected. I mention all this because I'm concerned about this pattern potentially masking other problems elsewhere in the tests.