-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
Discard unused body of Unary and ClientStream methods in background #5331
base: main
Are you sure you want to change the base?
Conversation
Forgot to regenerate files. Doing it now. |
Missing import for sync.WaitGroup. I don't feel like tinkering with the import machinery - and benchmarks don't show any significant slowdown when using channels instead. I'll update the implementation to use plain channels. |
I'll try to write an integration test for this too. |
Apparently, transactional request-response flow is inherent to Go HTTP, including grpc-gateway runtime. @johanbrandhorst |
Sure, it'd be great to know if we break the websocket proxy again in the future, why not! |
I've opened a repository for the websocket proxy itself: It's fairly covered with tests, which fail on |
Please see: #5338 |
Integration tests are failing even with the new changes :) good thing we decided to include them. Unfortunately, seems like the very act of waiting for This is certainly not desirable behavior - we want clients to be disconnected when server returns. That only leaves us with I will revert the commits replacing the |
Is it only affecting server side streaming methods, or bi-directional methods too? |
It happens on Unary methods and Server Stream methods (i.e. non-client-stream methods). Bidirectional and Client Stream methods don't use this template branch, so the problem doesn't apply - and neither does the root issue in which gateway doesn't read client body... In other news, I'm having trouble with properly testing WebSocket context cancellation:
Since WebSocket proxy layer cannot possibly know which method is going to be executed, we cannot decide what to do on WS close message:
In an ideal world, grpc-gateway would generate the WebSocket proxy itself, and it would generate two different implementations depending on the method type. Maybe that would be a cool feature in the future? So yeah, this is going to be a hairy one. I'll try to figure something out. |
I think @tmc has wanted to integrate the websocket proxy into the gateway for a long time but we just haven't decided the best way forward. I think it would be a bigger task than this issue. If we have to choose between supporting the websocket proxy and removing a bug in the gateway (#5236), then we're going to fix the bug. It might be good enough that we support the websocket proxy only for bi-directional streaming methods? |
Eh, you're right. I'm way too deep in the rabbit hole. So I can use both 1) coder/websocket library, as suggested, and 2) your suggestion to wait for io.Copy at end of the request. For any further bugs and features, I'll open new issues and possibly further PRs. |
Will test how this works with https://github.com/jnis23/grpc-gateway-proxy-example provided by the bug report. |
From example provided by the bug report, even "working" server-stream (with body) doesn't properly close websocket methods. And since server-stream request needs to return before request body is closed (in case of websockets), we should add I'll add that to templates and integration test as well... |
Integration tests are failing on Let me know if there's anything else I need to do. |
{{- end }} | ||
go io.Copy(io.Discard, req.Body) |
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.
Did you mean to do this unconditionally? I thought we were only doing this on body-less endpoints.
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.
One of the issues that I've noticed in the https://github.com/jnis23/grpc-gateway-proxy-example is that even the "working" example (the one with "body" defined) seems to have issues with closing connections.
After adding the go io.Copy
to those too, the issue disappeared.
In both Unary and ServerStream methods, client sends a finite amount of data before server stops reading the req.Body
(zero if body
is not defined in proto, request-message-length if body is defined in proto).
In both cases, not reading the req.Body
further causes the connections to hang.
Since server does not care for any input after those, we can safely do go io.Copy
on the request body.
Here's a screen recording of the issue:
report.mp4
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 just had a crazy thought - what about if we defer req.Body.Close
? How does that change the behavior?
I've modified the PR name to better align with changes. |
When
io.Copy
is called synchronously on HTTP request body, it stalls the clients who keep the request stream open.This broke WebSocket gateway implementations which rely on Close detection to know when to terminate.
This PR runs the
io.Copy
method in the background.References to other Issues or PRs
Fixes #5326.
Have you read the Contributing Guidelines?
Yes.
Brief description of what is fixed or changed
Added
go
keyword in front ofio.Copy
call in the template whenbody
annotation is not set.Other comments