-
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
Add sample code for setting and reading error details #506
Add sample code for setting and reading error details #506
Conversation
|
||
// Contact the server and capture the trailer metadata in md using a call option. | ||
r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name}, grpc.Trailer(&md)) | ||
if err != nil { |
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.
one thing I was trying to figure out is that:
is this error a rpc error from server side or this is a client-side/network 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.
I think the best way to check that would be to test the error code:
grpc.Code(err) != codes.Unknown
From the docs:
Code returns the error code for err if it was produced by the rpc system. Otherwise, it returns codes.Unknown.
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 what I am doing. However, in the doc it also says https://github.com/grpc/grpc-go/blob/master/codes/codes.go#L53.
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.
Network errors should be Unavailable
IIRC.
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.
checking error code is not right way to differentiate client and server side errors. The common practice is that the server application need pack a bit more info into the error description (e.g., serialized error protobuf).
@kelseyhightower Thanks! This is what I wanted to add after I tried to understand errors and had to read the grpc code a little bit. |
CC: @iamqizhao for review |
The example and the tutorial text look great to me, and the way it's done in Go is refreshingly easy. I'm not fluent enough to review the Go code in detail, though. If it's not too much to ask, it would be ideal if one of the standard error-detail protos were sent in the trailers (for example, |
@jcanizales I maybe missing something, but it seems I can only set the trailers once using grpc.SetTrailer. This function only takes a metadata type, which supports basic string key/value pairs. I'm not sure where to return the QuotaFailure message. Again, I maybe overlooking something. |
Oh, interesting! @iamqizhao, how does one set binary headers/trailers in the Go library? @kelseyhightower, this is exactly the kind of things I expect we'll find as we create these samples across all languages :) |
There is nothing special for setting binary value. You only need to make sure the key has a "-bin" suffix. |
// SayHello implements helloworld.GreeterServer | ||
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { | ||
// Track the number of times the user has been greeted. | ||
s.count[in.Name] += 1 |
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 think the goal of this example is to demonstrate how to set and read error details. I am wondering if involving metadata handling makes it over complicated.
BTW, you need mutex to guard the access of s.count. It is racy if you have multiple concurrent clients.
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.
Re: metadata, see grpc/grpc#4543, whose Go version this PR is trying to solve.
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 see. Then I need think through how this can be achieved in a nice way.
What's the function to serialize a proto message into a |
Error details may now be transmitted using status.FromProto instead of trailer metadata, and received via status.FromError().Proto().Details. An example for this could be added to the route_guide example, possibly by returning an error instead of an unnamed feature when nothing is found here: https://github.com/grpc/grpc-go/blob/master/examples/route_guide/server/server.go#L82. |
To be clear: On the wire, they'll be sent as trailer metadata, correct? It's important that all languages interoperate in this respect. |
On the wire, it's proto-serialized and sent with the trailer metadata as "grpc-status-details-bin". It's not available through the metadata handed back to the user, however -- it's returned to the client in the error. |
What's the type of the proto sent there? And can we confirm that |
It's a google.rpc.Status proto: https://github.com/grpc/grpc-go/blob/master/status/status.go#L131 The C and Java repos have also implemented this: https://github.com/grpc/grpc/blob/master/include/grpc%2B%2B/impl/codegen/call.h#L67 I believe their implementations do not create or parse that field as a proto by default, to avoid the proto dependency. They have libraries to create/parse the field instead. But in Go, grpc already has a dependency on proto, and status is generally handled differently, so it made more sense to implement it through the errors returned by the library. |
Fixes #478.