-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
deprecate stream, move documentation to client|server stream #2198
Conversation
Deprecate Stream, and move the methods and documention to ServerStream and ClientStream. This is due to the fact that there are different semantics for SendMsg, and it's quite confusing to document one method for two things. Furthermore, Stream is not actually used in any way other than to be inherited by ClientStream and ServerStream. Relevant issue: grpc#2159
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 doing this, I think it will be a big help!
stream.go
Outdated
// But it is not safe to call RecvMsg on the same stream in different goroutines. | ||
RecvMsg(m interface{}) error | ||
} | ||
// DEPRECATED: See ClientStream and ServerStream documentation instead. |
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.
Nit: "Deprecated" (case) - it actually matters to tools like staticcheck.
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.
Done.
stream.go
Outdated
|
||
// ClientStream defines the interface a client stream has to satisfy. | ||
// All errors returned from ClientStream are compatible with the status package. |
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.
Nit: "from ClientStream methods"
(and ServerStream)
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.
Done, and applied similar change to ServerStream.
stream.go
Outdated
RecvMsg(m interface{}) error | ||
} | ||
// DEPRECATED: See ClientStream and ServerStream documentation instead. | ||
type Stream interface {} | ||
|
||
// ClientStream defines the interface a client stream has to satisfy. |
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.
"ClientStream defines the client-side behavior of a streaming RPC."?
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.
Done, and applied a similar change to ServerStream.
stream.go
Outdated
// Context returns the context for this stream. | ||
Context() context.Context | ||
// SendMsg is generally called by generated code. On error, SendMsg aborts | ||
// the stream and returns an io.EOF; the status may be determined by |
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.
"On error, SendMsg aborts the stream. If the error was generated by the client, the status is returned directly; otherwise, io.EOF is returned and the status of the stream may be discovered using RecvMsg."
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.
Done.
stream.go
Outdated
// inspecting the error returned by calling RecvMsg. | ||
// | ||
// SendMsg blocks until: | ||
// - It schedules m with the transport, or |
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.
How about: "- There is sufficient flow control to schedule m with the transport, or"
...or something to indicate that we aren't just letting people queue up a billion messages.
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.
Done.
stream.go
Outdated
// SendMsg does not wait for an ack. An untimely stream closure can result | ||
// in any buffered messages along the way (including those in the | ||
// client-side buffer that comes with gRPC by default) being lost. To | ||
// ensure delivery, users must call RecvMsg until receiving an EOF before |
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.
This is painfully explicit IMO. How about:
"SendMsg does not wait until the message is received by the server. An untimely stream closure may result in lost messages. To ensure delivery, users should ensure the RPC completed successfully using RecvMsg."
The idea would be to refer people to RecvMsg and make sure we document it well enough there.
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.
That is really good. 👍
Done.
stream.go
Outdated
Stream | ||
// It's safe to have a goroutine calling SendMsg and another goroutine | ||
// calling RecvMsg on the same stream at the same time. It is not safe | ||
// to call SendMsg on the same stream in different goroutines. |
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.
"to call SendMsg or CloseSend"
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.
Done. Good call.
stream.go
Outdated
// calling RecvMsg on the same stream at the same time. It is not safe | ||
// to call SendMsg on the same stream in different goroutines. | ||
SendMsg(m interface{}) error | ||
// RecvMsg blocks until it receives a message or the stream is done. On |
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.
Let's remove the client/server language:
RecvMsg blocks until it receives a message into m or the stream is done. It returns io.EOF when the stream completes successfully. On any other error, it the stream is aborted and the error contains the RPC status.
It is safe to have a goroutine calling SendMsg and another goroutine calling RecvMsg on the same stream at the same time, but it is not safe to call RecvMsg on the same stream in different goroutines.
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.
Done.
stream.go
Outdated
// - The stream is done, or | ||
// - The stream breaks. | ||
// | ||
// SendMsg does not wait for an ack. An untimely stream closure can result |
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.
Same comment as above.
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.
Done.
stream.go
Outdated
// calling RecvMsg on the same stream at the same time. It is not safe | ||
// to call SendMsg on the same stream in different goroutines. | ||
SendMsg(m interface{}) error | ||
// RecvMsg blocks until it receives a message or the stream is done. On |
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.
Please remove client/server language here.
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.
Done (copy paste from above).
All comments addressed; PTAL at your convenience. |
Wait, ignore that, github was hiding ones from me. Fixing the outstanding ones! |
stream.go
Outdated
// It's safe to have a goroutine calling SendMsg and another goroutine | ||
// calling RecvMsg on the same stream at the same time. It is not safe | ||
// to call SendMsg on the same stream in different goroutines. | ||
// RecvMsg blocks until it receives a message into m or the stream is |
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 deleted SendMsg
by mistake.
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.
Who needs it! :)
Jk, added back in.
stream.go
Outdated
@@ -145,7 +144,7 @@ func (cc *ClientConn) NewStream(ctx context.Context, desc *StreamDesc, method st | |||
|
|||
// NewClientStream is a wrapper for ClientConn.NewStream. | |||
// | |||
// DEPRECATED: Use ClientConn.NewStream instead. | |||
// Deprecated: Use ClientConn.NewStream instead. |
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.
Let's not change this just yet...generated code still uses this (so vet fails).
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.
Done. Ditto for ServerStream and Stream?
// Stream.SendMsg() may return a non-nil error when something wrong happens sending | ||
// the request. The returned error indicates the status of this sending, not the final | ||
// status of the RPC. | ||
// Context returns the context for this stream. |
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.
Sorry...can you add this, too (only for ClientStream
):
It should not be called until after Header or RecvMsg has returned. Once called, subsequent client-side retries are disabled.
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.
Done. Good note - that's unexpected (to me).
// - The stream is done, or | ||
// - The stream breaks. | ||
// | ||
// SendMsg does not wait until the message is received by the server. An |
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.
s/server/client/
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.
Done. Good find.
// - The stream breaks. | ||
// | ||
// SendMsg does not wait until the message is received by the server. An | ||
// untimely stream closure may result in lost messages. To ensure delivery, |
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 server can never know whether the client received the message without something in the user's protocol.
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.
Right - this line alludes to that. I could more strongly state that by adjusting the line to:
"SendMsg does not wait until the message is received by the client. Users who need per-message acknowledgement are expected to implement it on top of gRPC."
Though, I don't know how much value there is in that. I kind of think the brevity of just saying, "we don't wait" is enough of a warning. Thoughts?
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.
SGTM
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.
Will you update this? The bit about "ensure the RPC completed successfully using RecvMsg" is misleading/wrong on the server-side.
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.
Ping on this comment..
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.
Shoot, sorry to have missed this. Hm, good point - that just means the client has finished sending their messages. Bad copy paste. I'm not sure it's worth saying, but is it correct to say that once the server returns in the handler, all messages will have been sent successfully? Or is the promise still only that messages have been scheduled? In short, is there any way to ensure all server messages have arrived? (I think not, but want to make sure I ask)
In the meantime, I've simply removed the line about RecvMsg. I neglected to include the line about per-message acks, since it doesn't seem to add too much more.
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'm not sure it's worth saying, but is it correct to say that once the server returns in the handler, all messages will have been sent successfully?
No, the server never knows whether a message is received by the client unless the user builds their own acks into their protocol. I think what you were proposing before was fine: "SendMsg does not wait until the message is received by the client."
stream.go
Outdated
// to call SendMsg or CloseSend on the same stream in different goroutines. | ||
SendMsg(m interface{}) error | ||
// RecvMsg blocks until it receives a message into m or the stream is | ||
// done. It returns io.EOF when the stream completes successfully. On |
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.
On the server, io.EOF
should not be returned.
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.
nil, I assume?
(changed it as such on that assumption)
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.
wait...did I write that?
RecvMsg
does return io.EOF
, but it's when the client does CloseSend
, not when the stream completes. Sorry.
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.
Done - added back in io.EOF documentation.
Heh no prob :)
stream.go
Outdated
// | ||
// It is safe to have a goroutine calling SendMsg and another goroutine | ||
// calling RecvMsg on the same stream at the same time, but it is not safe | ||
// to call SendMsg or CloseSend on the same stream in different goroutines. |
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 "or CloseSend" only applies to the client, not the server. The server doesn't have a CloseSend. Sorry if I put my comment in the wrong place earlier.
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.
Done. (that make sense)
stream.go
Outdated
// to call SendMsg on the same stream in different goroutines. | ||
SendMsg(m interface{}) error | ||
// RecvMsg blocks until it receives a message into m or the stream is done. | ||
// It returns io.EOF when the stream completes successfully. On any non-EOF |
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 returns io.EOF when the client has performed a CloseSend."?
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.
Done.
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.
.
Deprecate Stream, and move the methods and documention to ServerStream
and ClientStream. This is due to the fact that there are different
semantics for SendMsg, and it's quite confusing to document one method
for two things. Furthermore, Stream is not actually used in any way
other than to be inherited by ClientStream and ServerStream.
Relevant issue: #2159