Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The LUCI Authors. All rights reserved. | 1 // Copyright 2016 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 package grpcutil | 5 package grpcutil |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "github.com/luci/luci-go/common/errors" | |
| 9 | |
| 10 "google.golang.org/grpc" | 8 "google.golang.org/grpc" |
| 11 "google.golang.org/grpc/codes" | 9 "google.golang.org/grpc/codes" |
| 10 | |
| 11 "github.com/luci/luci-go/common/errors" | |
| 12 "github.com/luci/luci-go/common/retry/transient" | |
| 12 ) | 13 ) |
| 13 | 14 |
| 14 var ( | 15 var ( |
| 15 // Errf falls through to grpc.Errorf, with the notable exception that it isn't | 16 // Errf falls through to grpc.Errorf, with the notable exception that it isn't |
| 16 // named "Errorf" and, consequently, won't trigger "go vet" misuse error s. | 17 // named "Errorf" and, consequently, won't trigger "go vet" misuse error s. |
| 17 Errf = grpc.Errorf | 18 Errf = grpc.Errorf |
| 18 | 19 |
| 19 // OK is an empty grpc.OK status error. | 20 // OK is an empty grpc.OK status error. |
| 20 OK = Errf(codes.OK, "") | 21 OK = Errf(codes.OK, "") |
| 21 | 22 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 74 // If the supplied error is nil, nil will be returned. | 75 // If the supplied error is nil, nil will be returned. |
| 75 // | 76 // |
| 76 // Note that non-gRPC errors will have code grpc.Unknown, which is considered | 77 // Note that non-gRPC errors will have code grpc.Unknown, which is considered |
| 77 // transient, and be wrapped. This function should only be used on gRPC errors. | 78 // transient, and be wrapped. This function should only be used on gRPC errors. |
| 78 func WrapIfTransient(err error) error { | 79 func WrapIfTransient(err error) error { |
| 79 if err == nil { | 80 if err == nil { |
| 80 return nil | 81 return nil |
| 81 } | 82 } |
| 82 | 83 |
| 83 if IsTransientCode(Code(err)) { | 84 if IsTransientCode(Code(err)) { |
| 84 » » err = errors.WrapTransient(err) | 85 » » err = transient.Tag.Apply(err) |
| 85 } | 86 } |
| 86 return err | 87 return err |
| 87 } | 88 } |
| 88 | 89 |
| 89 const grpcCodeKey = "__grpcutil.Code" | 90 type grpcCodeTag struct{ Key errors.TagKey } |
|
dnj
2017/06/27 03:57:03
QQ: why is "Key" named here (and elsewhere)?
iannucci
2017/06/27 18:14:27
Because TagKey is a pointer type, it can't be embe
| |
| 91 | |
| 92 func (g grpcCodeTag) With(code codes.Code) errors.TagValue { return errors.MkTag Value(g.Key, code) } | |
| 93 func (g grpcCodeTag) In(err error) (v codes.Code, ok bool) { | |
| 94 » d, ok := errors.TagValueIn(g.Key, err) | |
| 95 » if ok { | |
| 96 » » v = d.(codes.Code) | |
| 97 » } | |
| 98 » return | |
| 99 } | |
| 100 | |
| 101 // Tag may be used to associate a gRPC status code with this error. | |
| 102 // | |
| 103 // The tag value MUST be a "google.golang.org/grpc/codes".Code. | |
| 104 var Tag = grpcCodeTag{errors.NewTagKey("gRPC Code")} | |
| 90 | 105 |
| 91 // Code returns the gRPC code for a given error. | 106 // Code returns the gRPC code for a given error. |
| 92 // | 107 // |
| 93 // In addition to the functionality of grpc.Code, this will unwrap any wrapped | 108 // In addition to the functionality of grpc.Code, this will unwrap any wrapped |
| 94 // errors before asking for its code. | 109 // errors before asking for its code. |
| 95 func Code(err error) codes.Code { | 110 func Code(err error) codes.Code { |
| 96 » if code := errors.ExtractData(err, grpcCodeKey); code != nil { | 111 » if code, ok := Tag.In(err); ok { |
| 97 » » return code.(codes.Code) | 112 » » return code |
| 98 } | 113 } |
| 99 return grpc.Code(errors.Unwrap(err)) | 114 return grpc.Code(errors.Unwrap(err)) |
| 100 } | 115 } |
| 101 | 116 |
| 102 // Annotate begins annotating the error, and adds the given gRPC code. | |
| 103 // This code may be extracted with the Code function in this package. | |
| 104 func Annotate(err error, code codes.Code) *errors.Annotator { | |
| 105 return errors.Annotate(err).D(grpcCodeKey, code) | |
| 106 } | |
| 107 | |
| 108 // ToGRPCErr is a shorthand for Errf(Code(err), "%s", err) | 117 // ToGRPCErr is a shorthand for Errf(Code(err), "%s", err) |
| 109 func ToGRPCErr(err error) error { | 118 func ToGRPCErr(err error) error { |
| 110 return Errf(Code(err), "%s", err) | 119 return Errf(Code(err), "%s", err) |
| 111 } | 120 } |
| 112 | 121 |
| 113 // IsTransientCode returns true if a given gRPC code is associated with a | 122 // IsTransientCode returns true if a given gRPC code is associated with a |
| 114 // transient gRPC error type. | 123 // transient gRPC error type. |
| 115 func IsTransientCode(code codes.Code) bool { | 124 func IsTransientCode(code codes.Code) bool { |
| 116 switch code { | 125 switch code { |
| 117 case codes.Internal, codes.Unknown, codes.Unavailable: | 126 case codes.Internal, codes.Unknown, codes.Unavailable: |
| 118 return true | 127 return true |
| 119 | 128 |
| 120 default: | 129 default: |
| 121 return false | 130 return false |
| 122 } | 131 } |
| 123 } | 132 } |
| OLD | NEW |