-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
client: fix upload timeouts with sock_read set #7150
client: fix upload timeouts with sock_read set #7150
Conversation
bd62e41
to
4651b63
Compare
4651b63
to
aa11d7f
Compare
Codecov Report
@@ Coverage Diff @@
## master #7150 +/- ##
=======================================
Coverage 97.37% 97.38%
=======================================
Files 106 106
Lines 31093 31113 +20
Branches 3875 3876 +1
=======================================
+ Hits 30278 30298 +20
Misses 613 613
Partials 202 202
Flags with carried forward coverage won't be shown. Click here to find out more.
📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
I'm wondering if this is the correct behaviour. If the timeout relates to reading data, shouldn't we start the timeout after we've finished writing? Or do we need to handle cases where reading happens simultaneously to writing? Currently, it looks like we start writing as a task: Then we start the response immediately after, which initialises the timer: Also, wouldn't this issue also occur if you tried to send a large payload without chunking? I'm not sure this fix works in that case. @webknjaz Thoughts? |
I also asked myself that question. I guess one of the use cases is to start reading the response while the file is being uploaded in order to catch potential errors early and abort the upload, although there's currently no mechanism for that: whole file is uploaded even if the server immediately returns an error (e.g. 401). In my limited testing, curl -X PUT -H "Transfer-Encoding: chunked" http://localhost:8472/file -T <large file> Fails immediately if the server returns a 401: async def handler(request: aiohttp.web.Request) -> aiohttp.web.Response:
return aiohttp.web.Response(status=401) Also note that the sock read timeout is actually started before we send the request (via aiohttp/aiohttp/client_proto.py Lines 146 to 160 in 743c21f
Good point, that's still broken, and the current fix is also broken when the time to upload a single chunk is comparable to the timeout value. Another proposal to fix this could be something like this: diff --git a/aiohttp/client.py b/aiohttp/client.py
index c4074577..8ceeeb09 100644
--- a/aiohttp/client.py
+++ b/aiohttp/client.py
@@ -525,6 +525,9 @@ class ClientSession:
try:
try:
resp = await req.send(conn)
+ conn.protocol.pause_reading()
+ await resp.wait_for_close()
+ conn.protocol.resume_reading()
try:
await resp.start(conn)
except BaseException: would fix the issue for all cases although I'm not sure it makes sense to completely pause reading while uploading. Any thoughts? |
I think you're probably right. I wonder if there's a reasonable way to only start the read timeout once the write has completed, even if we're already waiting on the read... |
If we can use that e.g. The timeout might be modified to do something like:
|
I think it might be easier to do something like this: diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py
index 9478e8d3..a11a600f 100644
--- a/aiohttp/client_reqrep.py
+++ b/aiohttp/client_reqrep.py
@@ -525,6 +525,7 @@ class ClientRequest:
protocol = conn.protocol
assert protocol is not None
+ protocol.drop_timeout()
try:
if isinstance(self.body, payload.Payload):
await self.body.write(writer)
@@ -551,6 +552,8 @@ class ClientRequest:
protocol.set_exception(exc)
except Exception as exc:
protocol.set_exception(exc)
+ else:
+ protocol.reschedule_timeout()
finally:
self._writer = None This works in every case we discussed above and does not block reading (note that I renamed Somewhat related: if the total timeout is not set, this could result in hangs while uploading since there's no |
This looks promising to me. Might be cleaner to skip the The only other code I see using this is in connector.py, and appears that it should adopt the same logic. |
@webknjaz There's no reason to expect So, should be safe to change the timeout logic in that class? |
aa11d7f
to
9159c7c
Compare
If we want to modify |
159730b
to
bb708d9
Compare
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'll wait for @webknjaz to confirm as well, but this looks good to me.
Adding a write timeout, as you mentioned before, is probably a good idea. But, maybe best to do it in a second PR. |
ca7cc0b
to
2c8c17b
Compare
Thanks @Dreamsorcerer. I'll try and find time to implement the write timeout in the next few weeks. |
Might need a bit of testing, but I'd expect the server to close the connection in that case, which should cause the write code to error. |
That's indeed the behaviour, a simpler test setup shows this. The error I was seeing was due to a blocking call in my code. |
Start the sock_read timeout handler after the payload body has been fully written.
2f702a3
to
303d3c0
Compare
Hi, is there anything I can do to help this get merged? Thanks! |
Think this is good now. Would be great to get that write_timeout in a new PR. |
Backport to 3.9: 💔 cherry-picking failed — conflicts found❌ Failed to cleanly apply fecbe99 on top of patchback/backports/3.9/fecbe999c7a110fbeba8aa6ba269497435b2870d/pr-7150 Backporting merged PR #7150 into master
🤖 @patchback |
Prevent the `sock_read` timeout callback from firing by only scheduling it afterthe payload (if any) has been fully written. No Fixes #7149 - [x] I think the code is well written - [x] Unit tests for the changes exist - [x] Documentation reflects the changes - [x] If you provide code modification, please add yourself to `CONTRIBUTORS.txt` * The format is <Name> <Surname>. * Please keep alphabetical order, the file is sorted by names. - [x] Add a new news fragment into the `CHANGES` folder * name it `<issue_id>.<type>` for example (588.bugfix) * if you don't have an `issue_id` change it to the pr id after creating the pr * ensure type is one of the following: * `.feature`: Signifying a new feature. * `.bugfix`: Signifying a bug fix. * `.doc`: Signifying a documentation improvement. * `.removal`: Signifying a deprecation or removal of public API. * `.misc`: A ticket has been closed, but it is not of interest to users. * Make sure to use full sentences with correct case and punctuation, for example: "Fix issue with non-ascii contents in doctest text files." --------- Co-authored-by: Sam Bull <[email protected]> (cherry picked from commit fecbe99)
Prevent the `sock_read` timeout callback from firing by only scheduling it afterthe payload (if any) has been fully written. No Fixes #7149 - [x] I think the code is well written - [x] Unit tests for the changes exist - [x] Documentation reflects the changes - [x] If you provide code modification, please add yourself to `CONTRIBUTORS.txt` * The format is <Name> <Surname>. * Please keep alphabetical order, the file is sorted by names. - [x] Add a new news fragment into the `CHANGES` folder * name it `<issue_id>.<type>` for example (588.bugfix) * if you don't have an `issue_id` change it to the pr id after creating the pr * ensure type is one of the following: * `.feature`: Signifying a new feature. * `.bugfix`: Signifying a bug fix. * `.doc`: Signifying a documentation improvement. * `.removal`: Signifying a deprecation or removal of public API. * `.misc`: A ticket has been closed, but it is not of interest to users. * Make sure to use full sentences with correct case and punctuation, for example: "Fix issue with non-ascii contents in doctest text files." --------- Co-authored-by: Sam Bull <[email protected]> (cherry picked from commit fecbe99) <!-- Thank you for your contribution! --> ## What do these changes do? <!-- Please give a short brief about these changes. --> ## Are there changes in behavior for the user? <!-- Outline any notable behaviour for the end users. --> ## Related issue number <!-- Are there any issues opened that will be resolved by merging this change? --> ## Checklist - [ ] I think the code is well written - [ ] Unit tests for the changes exist - [ ] Documentation reflects the changes - [ ] If you provide code modification, please add yourself to `CONTRIBUTORS.txt` * The format is <Name> <Surname>. * Please keep alphabetical order, the file is sorted by names. - [ ] Add a new news fragment into the `CHANGES` folder * name it `<issue_id>.<type>` for example (588.bugfix) * if you don't have an `issue_id` change it to the pr id after creating the pr * ensure type is one of the following: * `.feature`: Signifying a new feature. * `.bugfix`: Signifying a bug fix. * `.doc`: Signifying a documentation improvement. * `.removal`: Signifying a deprecation or removal of public API. * `.misc`: A ticket has been closed, but it is not of interest to users. * Make sure to use full sentences with correct case and punctuation, for example: "Fix issue with non-ascii contents in doctest text files." Co-authored-by: daniele <[email protected]>
What do these changes do?
Prevent the
sock_read
timeout callback from firing by only scheduling it afterthe payload (if any) has been fully written.Are there changes in behavior for the user?
No
Related issue number
Fixes #7149
Checklist
CONTRIBUTORS.txt
CHANGES
folder<issue_id>.<type>
for example (588.bugfix)issue_id
change it to the pr id after creating the pr.feature
: Signifying a new feature..bugfix
: Signifying a bug fix..doc
: Signifying a documentation improvement..removal
: Signifying a deprecation or removal of public API..misc
: A ticket has been closed, but it is not of interest to users.