-
Notifications
You must be signed in to change notification settings - Fork 96
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
New grpcadapter package to transcode connect and gRPC-Web #527
Conversation
* Add test for errors marshaling protobuf Status If a user-supplied Codec errors when marshaling a protobuf Status message (which we use internally when converting errors to HTTP trailers), we currently drop all the error information on the floor and return "Unknown: EOF". This commit adds a reproduction as a test case. Relates to #197. * Use CodeInternal for errors marshaling proto Status If we can't marshal a protobuf Status message, send CodeInternal to the client with some details. * Fix error-wrapping lint
So that we can share code between our implementations of the Connect and gRPC protocols, factor enveloping (aka length-prefixed messages) and compression out of the gRPC-specific code.
* Add test for unary RPC with zero-byte messages * Add failing test for handler timeout handling We're parsing timeouts, but not properly propagating them into user code. Thanks, crosstests! * Fix timeout handling Since we know the shape of the Connect protocol, we can simplify the protocol interfaces and move some shared utility functions into `protocol.go`. This also fixes server-side timeout handling. * Keep Accept-Post string manipulation shorter We're only doing this at startup, so it's okay to make it slow. The code doesn't get much shorter, but it's arguably more readable. * Add indirection to constant limit Move the literal for our discard limit into a constant.
…nable to be sent (#211) Co-authored-by: Steve Ayers <sayers@uber.com>
In preparation for factoring out some of the complicated HTTP stuff happening in the gRPC client stream implementation, move timeout encoding to a less-convoluted portion of the code.
The most complex portion of the client-side gRPC sender and receiver is the HTTP layer, where we use `io.Pipe` to create a streaming request body. So that we can reuse this code for the Connect protocol, factor it out of the gRPC-specific code. This has the side effect of simplifying the gRPC implementation and more clearly separating the gRPC and gRPC-Web protocols.
The params structs for protocols are somewhat proven now, so we can stop hand-copying them into protocol-specific structs and embed instead.
Make all the gRPC headers constants and prefix a few unexported utility functions that snuck through.
If we're not using the receiver, leave it unnamed.
Use Connect's canonical string representation for error codes.
We use sender and receiver wrappers to make sure that all public APIs return *Errors. Factor these out of the gRPC code, since they're equally applicable to Connect.
d717a91
to
c019158
Compare
grpcadapter/transport.go
Outdated
// binary Protobuf format, even if the messages in the request/response stream | ||
// use a different codec. Consequently, this function needs a Protobuf codec to | ||
// unmarshal error information in the headers. | ||
func grpcErrorFromTrailer(trailer http.Header) *connect.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.
Copied from protocol_grpc.go
grpcadapter/transport.go
Outdated
return base64.NewDecoder(base64.URLEncoding, stringReader) | ||
} | ||
|
||
func queryValueReader(data string, base64Encoded bool) io.Reader { |
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.
Copied from protocol_connect.go
.
Use the `MarshalAppend` methods introduced in v1.31 of the protobuf runtime to more aggressively reuse buffers from Connect's internal pool (for both binary and JSON). This reduces allocations and substantially improves throughput: ``` BenchmarkConnect/unary-12 8054 1318347 ns/op 14414394 B/op 251 allocs/op BenchmarkConnect/unary-12 10448 1153636 ns/op 6115680 B/op 236 allocs/op ``` --------- Co-authored-by: Akshay Shah <akshay@akshayshah.org>
Capture unexpected io.EOF errors as io.ErrUnexpectedEOF in client streams. Now raises an error when the stream doesn't end with an end response message. Fixes https://github.com/bufbuild/connect-go/issues/397
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 really like the direction here - the user-facing API is super nice and clean! It's also much more decoupled from the internals of connect-go
than I expected, which is great - I'd love to keep this PR open until we've got github.com/connectrpc
ready to go, and then put this code into a separate repository.
A few notes on the code:
- Please follow the Go style guide. (Search Notion for "Code Standards.")
- Can we use the content-length header to buffer less when handling unary Connect RPCs?
Cover the gRPC and gRPC-Web protocols in the tests for `io.ErrUnexpectedEOF`, and ensure that error codes and observable `errors.Is` behavior is consistent for all 3 supported RPC protocols.
08625c5
to
06777b1
Compare
What's the status of this feature, and any indication on which version it'll appear in? |
We're splitting it out into a separate project, which we'll release under the https://github.com/connectrpc organization. It's being actively worked on by @emcfarlane and @jhump, so it's coming as soon as we get something really nice ready! |
That's great. Do you know if it will support existing unary server interceptors? We have a lot of existing interceptors we'd like to avoid having to rewrite or maintain 2x copies of. |
As things are shaping up now, the new package we're developing works with any |
Is there somewhere we could follow along the development of the forthcoming package? We're getting close to an internal decision point about technology, and having this available would really help. The number of internal existing golang gRPC services we have implemented means it wouldn't make sense to use connect without something like this. |
Also - we'd be very happy to beta-test! 🥳 |
Hey @timruffles, beta testing would be great! Will get something to you soon. |
Creates a new package
grpcadapter
(github.com/connect-go/grpcadapter
). Create a handlergrpcadapter.NewHandler
that can transcode connect and gRPC-web protocols to gRPC handlers. Allows gRPC go servers to use connect by wrappinggrpc.Server
.Unary connect requests are buffered and obey the limits set via connect options. For streams and gRPC-web these options are ignored and control is passed to the underlying gRPC handler.
Connect-crosstest is used to add more coverage: connectrpc/conformance#478
Closes https://github.com/bufbuild/connect-go/issues/334