-
Notifications
You must be signed in to change notification settings - Fork 421
Move reading of multipart response into try body
#19062
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
Conversation
Otherwise the exception will be raised outside of the error handling code.
| response, output_stream, boundary, expected_size + 1 | ||
| ) | ||
| deferred.addTimeout(self.default_timeout_seconds, self.reactor) | ||
| multipart_response = await make_deferred_yieldable(deferred) |
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.
Should this be inside the async with self.remote_download_linearizer.queue(ip_address):?
Maybe. We do it in get_file which is probably what federation_get_file was based off of:
synapse/synapse/http/matrixfederationclient.py
Lines 1578 to 1582 in da6c0ca
| async with self.remote_download_linearizer.queue(ip_address): | |
| # add a byte of headroom to max size as function errs at >= | |
| d = read_body_with_max_size(response, output_stream, expected_size + 1) | |
| d.addTimeout(self.default_timeout_seconds, self.reactor) | |
| length = await make_deferred_yieldable(d) |
And although this isn't explained anywhere, I guess the point of self.remote_download_linearizer is to ensure we only download 6 pieces of remote media at a time for some reason (maybe resource exhaustion, just a bunch of assumptions). So it makes sense that the download part is under the lock.
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 would argue yes. This code:
# add a byte of headroom to max size as `_MultipartParserProtocol.dataReceived` errs at >=
deferred = read_multipart_response(
response, output_stream, boundary, expected_size + 1
)
deferred.addTimeout(self.default_timeout_seconds, self.reactor)merely sets up the download, whereas:
multipart_response = await make_deferred_yieldable(deferred)is where we actually wait for the download to complete. So I would expect the lineariser to cover the latter.
I can't speak to why we limit the number of downloads. Potentially the limit the number of open file descriptors? But 6 seems quite low for only that reason. 🤷
| @@ -1758,6 +1719,7 @@ | |||
| response, output_stream, boundary, expected_size + 1 | |||
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.
Do we have tests for this kind of timeout? (just wondering)
It looks like this was previously functional and the only problem was the unexpected logs/error handling so a high-level integration/end-to-end test wouldn't have really prevented this.
It looks like we already have other tests in tests/http/test_matrixfederationclient.py that ensure we raise a RequestSendFailed in certain scenarios. We could add one of those 🤷
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.
Thanks for the pointer to the test file. I've written up a test (that fails on develop) in 1f20fe7.
The test checks that a `RequestSendFailed` wrapping a `defer.TimeoutError` is raised.. Whereas before the fix, a raw `defer.TimeoutError` was raised, which calling code wouldn't expect.
Otherwise the exception will be raised outside of the error handling code. Fixes #19061.
Missed in #17365.
Pull Request Checklist
EventStoretoEventWorkerStore.".code blocks.