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" | |
12 ) | 13 ) |
13 | 14 |
15 // Errf falls through to grpc.Errorf, but will tag the resulting error with | |
16 // retry.Tag if it's transient. | |
17 // | |
18 // This is named `Errf` so that it won't trigger "go vet" misuse errors. | |
19 func Errf(code codes.Code, fmt string, a ...interface{}) error { | |
20 ret := grpc.Errorf(code, fmt, a...) | |
21 if IsTransientCode(code) { | |
22 ret = retry.Tag.Apply(ret) | |
dnj
2017/06/24 14:53:55
This is concerning to me WRT current behavior. I l
iannucci
2017/06/24 20:16:10
I'll undo this for now then
| |
23 } | |
24 return ret | |
25 } | |
26 | |
14 var ( | 27 var ( |
15 // 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 Errf = grpc.Errorf | |
18 | |
19 // OK is an empty grpc.OK status error. | 28 // OK is an empty grpc.OK status error. |
20 OK = Errf(codes.OK, "") | 29 OK = Errf(codes.OK, "") |
21 | 30 |
22 // Canceled is an empty grpc.Canceled error. | 31 // Canceled is an empty grpc.Canceled error. |
23 Canceled = Errf(codes.Canceled, "") | 32 Canceled = Errf(codes.Canceled, "") |
24 | 33 |
25 // Unknown is an empty grpc.Unknown error. | 34 // Unknown is an empty grpc.Unknown error. |
26 Unknown = Errf(codes.Unknown, "") | 35 Unknown = Errf(codes.Unknown, "") |
27 | 36 |
28 // InvalidArgument is an empty grpc.InvalidArgument error. | 37 // InvalidArgument is an empty grpc.InvalidArgument error. |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
74 // If the supplied error is nil, nil will be returned. | 83 // If the supplied error is nil, nil will be returned. |
75 // | 84 // |
76 // Note that non-gRPC errors will have code grpc.Unknown, which is considered | 85 // 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. | 86 // transient, and be wrapped. This function should only be used on gRPC errors. |
78 func WrapIfTransient(err error) error { | 87 func WrapIfTransient(err error) error { |
79 if err == nil { | 88 if err == nil { |
80 return nil | 89 return nil |
81 } | 90 } |
82 | 91 |
83 if IsTransientCode(Code(err)) { | 92 if IsTransientCode(Code(err)) { |
84 » » err = errors.WrapTransient(err) | 93 » » err = retry.Tag.Apply(err) |
85 } | 94 } |
86 return err | 95 return err |
87 } | 96 } |
88 | 97 |
89 const grpcCodeKey = "__grpcutil.Code" | 98 // Tag may be used to associate a gRPC status code with this error. |
99 // | |
100 // The tag value MUST be a "google.golang.org/grpc/codes".Code. | |
101 var Tag = errors.NewTagger("gRPC Code", func(v interface{}) { | |
102 » _ = v.(codes.Code) | |
103 }) | |
90 | 104 |
91 // Code returns the gRPC code for a given error. | 105 // Code returns the gRPC code for a given error. |
92 // | 106 // |
93 // In addition to the functionality of grpc.Code, this will unwrap any wrapped | 107 // In addition to the functionality of grpc.Code, this will unwrap any wrapped |
94 // errors before asking for its code. | 108 // errors before asking for its code. |
95 func Code(err error) codes.Code { | 109 func Code(err error) codes.Code { |
96 » if code := errors.ExtractData(err, grpcCodeKey); code != nil { | 110 » if code, ok := Tag.ValueIn(err); ok { |
97 return code.(codes.Code) | 111 return code.(codes.Code) |
98 } | 112 } |
99 return grpc.Code(errors.Unwrap(err)) | 113 return grpc.Code(errors.Unwrap(err)) |
100 } | 114 } |
101 | 115 |
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) | 116 // ToGRPCErr is a shorthand for Errf(Code(err), "%s", err) |
109 func ToGRPCErr(err error) error { | 117 func ToGRPCErr(err error) error { |
110 return Errf(Code(err), "%s", err) | 118 return Errf(Code(err), "%s", err) |
111 } | 119 } |
112 | 120 |
113 // IsTransientCode returns true if a given gRPC code is associated with a | 121 // IsTransientCode returns true if a given gRPC code is associated with a |
114 // transient gRPC error type. | 122 // transient gRPC error type. |
115 func IsTransientCode(code codes.Code) bool { | 123 func IsTransientCode(code codes.Code) bool { |
116 switch code { | 124 switch code { |
117 case codes.Internal, codes.Unknown, codes.Unavailable: | 125 case codes.Internal, codes.Unknown, codes.Unavailable: |
118 return true | 126 return true |
119 | 127 |
120 default: | 128 default: |
121 return false | 129 return false |
122 } | 130 } |
123 } | 131 } |
OLD | NEW |