-
Notifications
You must be signed in to change notification settings - Fork 112
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
Rework streaming interceptors #316
Conversation
Streaming interceptors aren't very useful in their current state. Rather than wrapping user code, they wrap the the networking primitives used by the user's code. This is a subtle distinction, but it makes it impossible to write a panic-recovering interceptor. It also makes common server-side interceptors (e.g., authentication) needlessly difficult to write. This commit reworks the Sender and Receiver interfaces into a ClientConn and HandlerConn. Just as unary interceptors wrap a UnaryFunc, streaming interceptors now wrap ClientConnFuncs and HandlerConnFuncs. This ends up being quite a bit easier to understand. Connect's internals change a lot, but the user-visible changes are modest. Today, we have: ```go type Sender interface { Spec() Spec Send(any) error Header() http.Header Trailer() (http.Header, bool) Close(error) error } type Receiver interface { Spec() Spec Receive(any) error Header() http.Header Trailer() (http.Header, bool) Close() error } type Interceptor interface { WrapUnary(UnaryFunc) UnaryFunc WrapStreamContext(context.Context) context.Context WrapStreamSender(context.Context, Sender) Sender WrapStreamReceiver(context.Context, Receiver) Receiver } ``` With this commit, we change to: ```go type ClientConn interface { Spec() Spec Send(any) error RequestHeader() http.Header CloseRequest() error Receive(any) error ResponseHeader() http.Header ResponseTrailer() http.Header CloseResponse() error } type HandlerConn interface { Spec() Spec Receive(any) error RequestHeader() http.Header Send(any) error ResponseHeader() http.Header ResponseTrailer() http.Header Close(error) error } type ClientConnFunc func(Spec, http.Header) ClientConn type HandlerConnFunc func(context.Context, HandlerConn) error type Interceptor interface { WrapUnary(UnaryFunc) UnaryFunc WrapStreamingClient(ClientConnFunc) ClientConnFunc WrapStreamingHandler(HandlerConnFunc) HandlerConnFunc } ``` Fixes #296.
_ = sender.Close(sender.Send(response.Any())) | ||
mergeHeaders(conn.ResponseHeader(), response.Header()) | ||
mergeHeaders(conn.ResponseTrailer(), response.Trailer()) | ||
return conn.Send(response.Any()) |
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.
We used to call sender.Close(...)
here - is that now replaced by: https://github.com/bufbuild/connect-go/pull/316/files#diff-0eb779b9e49d8e44b0f36923fdb8d87d5ee024f886eefc45deec4ec88380a087R210
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.
Yep!
Co-authored-by: Philip K. Warren <[email protected]>
Co-authored-by: Philip K. Warren <[email protected]>
Co-authored-by: Philip K. Warren <[email protected]>
Co-authored-by: Philip K. Warren <[email protected]>
I'm not going to go through all the code, but can we talk briefly offline about interfaces? Want to make sure I understand 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.
@akshayjshah and I talked offline, going to make a slight naming change, otherwise LGTM
Rename to make it clearer that the new Conn interfaces are only relevant to users of streaming RPCs.
* Rework streaming interceptors Streaming interceptors aren't very useful in their current state. Rather than wrapping user code, they wrap the the networking primitives used by the user's code. This is a subtle distinction, but it makes it impossible to write a panic-recovering interceptor. It also makes common server-side interceptors (e.g., authentication) needlessly difficult to write. This commit reworks the Sender and Receiver interfaces into a ClientConn and HandlerConn. Just as unary interceptors wrap a UnaryFunc, streaming interceptors now wrap ClientConnFuncs and HandlerConnFuncs. This ends up being quite a bit easier to understand. Connect's internals change a lot, but the user-visible changes are modest. Today, we have: ```go type Sender interface { Spec() Spec Send(any) error Header() http.Header Trailer() (http.Header, bool) Close(error) error } type Receiver interface { Spec() Spec Receive(any) error Header() http.Header Trailer() (http.Header, bool) Close() error } type Interceptor interface { WrapUnary(UnaryFunc) UnaryFunc WrapStreamContext(context.Context) context.Context WrapStreamSender(context.Context, Sender) Sender WrapStreamReceiver(context.Context, Receiver) Receiver } ``` With this commit, we change to: ```go type ClientConn interface { Spec() Spec Send(any) error RequestHeader() http.Header CloseRequest() error Receive(any) error ResponseHeader() http.Header ResponseTrailer() http.Header CloseResponse() error } type HandlerConn interface { Spec() Spec Receive(any) error RequestHeader() http.Header Send(any) error ResponseHeader() http.Header ResponseTrailer() http.Header Close(error) error } type ClientConnFunc func(Spec, http.Header) ClientConn type HandlerConnFunc func(context.Context, HandlerConn) error type Interceptor interface { WrapUnary(UnaryFunc) UnaryFunc WrapStreamingClient(ClientConnFunc) ClientConnFunc WrapStreamingHandler(HandlerConnFunc) HandlerConnFunc } ``` Fixes #296. * Fix flaky test * Update client_stream.go Co-authored-by: Philip K. Warren <[email protected]> * Update client_stream.go Co-authored-by: Philip K. Warren <[email protected]> * Update interceptor_ext_test.go Co-authored-by: Philip K. Warren <[email protected]> * Update interceptor_ext_test.go Co-authored-by: Philip K. Warren <[email protected]> * Also remove closing parens * Restructure concurrency GoDoc for ClientConn * Make missing trailers tests handle timing non-determinism * Avoid a few map allocations * Rename to Streaming*Conn Rename to make it clearer that the new Conn interfaces are only relevant to users of streaming RPCs. Co-authored-by: Philip K. Warren <[email protected]>
Streaming interceptors aren't very useful in their current state. Rather
than wrapping user code, they wrap the the networking primitives used by
the user's code. This is a subtle distinction, but it makes it
impossible to write a panic-recovering interceptor. It also makes common
server-side interceptors (e.g., authentication) needlessly difficult to
write.
This commit reworks the Sender and Receiver interfaces into a StreamingClientConn
and StreamingHandlerConn. Just as unary interceptors wrap a UnaryFunc, streaming
interceptors now wrap StreamingClientFuncs and StreamingHandlerFuncs. This ends up
being quite a bit easier to understand.
Connect's internals change a lot, but the user-visible changes are
modest. Today, we have:
With this commit, we change to:
Fixes #296.