| OLD | NEW |
| 1 // Copyright 2015 The LUCI Authors. | 1 // Copyright 2015 The LUCI Authors. |
| 2 // | 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
| 6 // | 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // | 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 // Return the same error again to continue retry behaviour, or nil to pretend | 47 // Return the same error again to continue retry behaviour, or nil to pretend |
| 48 // this error was a success. | 48 // this error was a success. |
| 49 type ErrorHandler func(resp *http.Response, err error) error | 49 type ErrorHandler func(resp *http.Response, err error) error |
| 50 | 50 |
| 51 // RequestGen is a generator function to create a new request. It may be called | 51 // RequestGen is a generator function to create a new request. It may be called |
| 52 // multiple times if an operation needs to be retried. The HTTP server is | 52 // multiple times if an operation needs to be retried. The HTTP server is |
| 53 // responsible for closing the Request body, as per http.Request Body method | 53 // responsible for closing the Request body, as per http.Request Body method |
| 54 // documentation. | 54 // documentation. |
| 55 type RequestGen func() (*http.Request, error) | 55 type RequestGen func() (*http.Request, error) |
| 56 | 56 |
| 57 var httpTagKey = errors.NewTagKey("this is an HTTP error") |
| 58 |
| 59 func applyHTTPTag(err error, status int) error { |
| 60 return errors.TagValue{Key: httpTagKey, Value: status}.Apply(err) |
| 61 } |
| 62 |
| 63 func IsHTTPError(err error) (status int, ok bool) { |
| 64 d, ok := errors.TagValueIn(httpTagKey, err) |
| 65 if ok { |
| 66 status = d.(int) |
| 67 } |
| 68 return |
| 69 } |
| 70 |
| 57 // NewRequest returns a retriable request. | 71 // NewRequest returns a retriable request. |
| 58 // | 72 // |
| 59 // The handler func is responsible for closing the response Body before | 73 // The handler func is responsible for closing the response Body before |
| 60 // returning. It should return retry.Error in case of retriable error, for | 74 // returning. It should return retry.Error in case of retriable error, for |
| 61 // example if a TCP connection is terminated while receiving the content. | 75 // example if a TCP connection is terminated while receiving the content. |
| 62 // | 76 // |
| 63 // If rFn is nil, NewRequest will use a default exponential backoff strategy | 77 // If rFn is nil, NewRequest will use a default exponential backoff strategy |
| 64 // only for transient errors. | 78 // only for transient errors. |
| 65 // | 79 // |
| 66 // If errorHandler is nil, the default error handler will drain and close the | 80 // If errorHandler is nil, the default error handler will drain and close the |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 Tag(transient.Tag).Err() | 124 Tag(transient.Tag).Err() |
| 111 case status >= 400: | 125 case status >= 400: |
| 112 // Any other failure code is a hard failure. | 126 // Any other failure code is a hard failure. |
| 113 err = fmt.Errorf("http request failed: %s (HTTP
%d)", http.StatusText(status), status) | 127 err = fmt.Errorf("http request failed: %s (HTTP
%d)", http.StatusText(status), status) |
| 114 default: | 128 default: |
| 115 // The handler may still return a retry.Error to
indicate that the request | 129 // The handler may still return a retry.Error to
indicate that the request |
| 116 // should be retried even on successful status c
ode. | 130 // should be retried even on successful status c
ode. |
| 117 return handler(resp) | 131 return handler(resp) |
| 118 } | 132 } |
| 119 | 133 |
| 134 err = applyHTTPTag(err, status) |
| 120 return errorHandler(resp, err) | 135 return errorHandler(resp, err) |
| 121 }, nil) | 136 }, nil) |
| 122 if err != nil { | 137 if err != nil { |
| 123 » » » err = fmt.Errorf("%v (attempts: %d)", err, attempts) | 138 » » » err = errors.Annotate(err, "gave up after %d attempts",
attempts).Err() |
| 124 } | 139 } |
| 125 return status, err | 140 return status, err |
| 126 } | 141 } |
| 127 } | 142 } |
| 128 | 143 |
| 129 // NewRequestJSON returns a retriable request calling a JSON endpoint. | 144 // NewRequestJSON returns a retriable request calling a JSON endpoint. |
| 130 func NewRequestJSON(ctx context.Context, c *http.Client, rFn retry.Factory, url,
method string, headers map[string]string, in, out interface{}) (func() (int, er
ror), error) { | 145 func NewRequestJSON(ctx context.Context, c *http.Client, rFn retry.Factory, url,
method string, headers map[string]string, in, out interface{}) (func() (int, er
ror), error) { |
| 131 var encoded []byte | 146 var encoded []byte |
| 132 if in != nil { | 147 if in != nil { |
| 133 var err error | 148 var err error |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 184 } | 199 } |
| 185 | 200 |
| 186 // PostJSON is a shorthand. It returns the HTTP status code and error if any. | 201 // PostJSON is a shorthand. It returns the HTTP status code and error if any. |
| 187 func PostJSON(ctx context.Context, rFn retry.Factory, c *http.Client, url string
, headers map[string]string, in, out interface{}) (int, error) { | 202 func PostJSON(ctx context.Context, rFn retry.Factory, c *http.Client, url string
, headers map[string]string, in, out interface{}) (int, error) { |
| 188 req, err := NewRequestJSON(ctx, c, rFn, url, "POST", headers, in, out) | 203 req, err := NewRequestJSON(ctx, c, rFn, url, "POST", headers, in, out) |
| 189 if err != nil { | 204 if err != nil { |
| 190 return 0, err | 205 return 0, err |
| 191 } | 206 } |
| 192 return req() | 207 return req() |
| 193 } | 208 } |
| OLD | NEW |