-
Notifications
You must be signed in to change notification settings - Fork 2.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
fix: loadbalance stream based on response #6122
fix: loadbalance stream based on response #6122
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #6122 +/- ##
==========================================
+ Coverage 73.86% 75.18% +1.32%
==========================================
Files 152 152
Lines 14069 14062 -7
==========================================
+ Hits 10392 10573 +181
+ Misses 3677 3489 -188
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
Hey @NarekA, Thanks for the contribution, can you check the failed tests and add a test showing what u are intending to fix? |
@JoanFM I think the issue came about because I was using |
e0a8118
to
d287848
Compare
|
||
async with _RequestContextManager( | ||
session._request(request.method, target_url, **request_kwargs) | ||
) as response: |
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.
@NarekA why not directly use the request
method from the session?, it's already wrapping the context manager for you.
def request(
self, method: str, url: StrOrURL, **kwargs: Any
) -> "_RequestContextManager":
"""Perform HTTP request."""
return _RequestContextManager(self._request(method, url, **kwargs))
```
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.
Somehow I missed this, will fix.
request_kwargs = { | ||
'headers': request.headers, | ||
'params': request.query, | ||
} |
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.
The original code did not forward the headers & query, which makes me wonder if it's intentional?
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.
it was not intentional
return web.Response( | ||
body=content, | ||
status=response.status, | ||
content_type=response.content_type, |
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 the header be added here as well?
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.
Also by looking at the original GET implementation, I wonder if we just need to use StreamResponse all the way. Basically the load balancer just stream whatever it receives out.
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.
yes this would be a good idea
Most of the errors on tests will be fixed by #6124 |
02d3979
to
42f444a
Compare
return web.Response( | ||
body=content, | ||
status=response.status, | ||
content_type=response.content_type, |
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.
Also by looking at the original GET implementation, I wonder if we just need to use StreamResponse all the way. Basically the load balancer just stream whatever it receives out.
if payload: | ||
request_kwargs['json'] = payload | ||
except Exception: | ||
self.logger.debug('No JSON payload found in request') |
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.
Looking at the original implementation, i have this idea:
it looks like the original logic was only to write a debug log which is not useful at all for production application. Can we just act as a pure proxy here for performance consideration? Something like:
async with session.request(request.method, data=request.iter_any(), **request_kwargs) as response:
....
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.
For some reason, if I try to pass the content in any other way besides the json field, I get an error here. I've tried everything at this point, if you can get this to work, I am interested.
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.
what error do you see?
@JoanFM I'm finding these tests to be prohibitively difficult to debug. Any idea what is going wrong? I need a better way of replicating them locally. |
self.logger.debug('No JSON payload found in request') | ||
|
||
async with session.request( | ||
request.method, url=target_url, **request_kwargs |
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.
You might consider adding auto_decompress=False
here. I've seen issue when upstream compresses the response, without this flag, together with the upstream header, there will be an error.
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, just fixed this.
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.
Looks like this fixed everything!
Thanks for this great contribution! |
The current load balancer assumes all
GET
requests are streaming and allPOST
requests are not. This may not be true for user-added fast-api endpoints and in the past we have talked about usingPOST
for streaming. (One of the benefits of this is the Swagger UI better documents the payload forPOST
endpoints).It makes more sense to use the response content-type to determine when to stream.
Goals: