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 |