Skip to content

Commit 85c4409

Browse files
authored
fix: only return last error of retry loop (propagated to the user) - log the rest (#5)
1 parent 5c0178f commit 85c4409

File tree

1 file changed

+19
-15
lines changed

1 file changed

+19
-15
lines changed

client.go

+19-15
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"errors"
99
"fmt"
1010
"io"
11+
"log/slog"
1112
"math/rand"
1213
"net/http"
1314
"slices"
@@ -156,12 +157,10 @@ func (c *Client) sendRequest(req *http.Request, v Response, retryOpts ...RetryOp
156157
bodyBytes, err = io.ReadAll(req.Body)
157158
_ = req.Body.Close()
158159
if err != nil {
159-
failures = append(failures, fmt.Sprintf("failed to read request body: %v", err))
160-
return fmt.Errorf("failed to read request body: %v; failures: %v", err, strings.Join(failures, "; "))
160+
return fmt.Errorf("failed to read request body: %v", err)
161161
}
162162
}
163163

164-
retryLoop:
165164
for i := 0; i <= options.Retries; i++ {
166165

167166
// Reset body to the original request body
@@ -189,21 +188,24 @@ retryLoop:
189188

190189
// exit on non-retriable status codes
191190
if !options.canRetry(resp.StatusCode) {
192-
failures = append(failures, fmt.Sprintf("exiting due to non-retriable error in try #%d/%d: %v", i+1, options.Retries+1, resp.StatusCode))
193-
return fmt.Errorf("request failed on non-retriable error: %v", strings.Join(failures, "; "))
191+
failures = append(failures, fmt.Sprintf("exiting due to non-retriable error in try #%d/%d: %d %s", i+1, options.Retries+1, resp.StatusCode, resp.Status))
192+
slog.Error("sendRequest failed due to non-retriable statuscode", "code", resp.StatusCode, "status", resp.Status, "tries", i+1, "maxTries", options.Retries+1, "failures", strings.Join(failures, "; "))
193+
return fmt.Errorf("request failed on non-retriable status-code: %d %s", resp.StatusCode, resp.Status)
194194
}
195195

196196
// exponential backoff
197197
delay := baseDelay * time.Duration(1<<i)
198198
jitter := time.Duration(rand.Int63n(int64(baseDelay)))
199199
select {
200200
case <-req.Context().Done():
201-
failures = append(failures, fmt.Sprintf("exiting due to canceled context after try #%d/%d: %v", i+1, options.Retries+1, req.Context().Err()))
202-
break retryLoop
201+
slog.Error("sendRequest failed due to canceled context", "tries", i+1, "maxTries", options.Retries+1, "failures", strings.Join(failures, "; "))
202+
return fmt.Errorf("request failed due to canceled context: %v", req.Context().Err())
203203
case <-time.After(delay + jitter):
204204
}
205205
}
206-
return fmt.Errorf("request failed %d times: %v", options.Retries+1, strings.Join(failures, "; "))
206+
207+
slog.Error("sendRequest failed after exceeding retry limit", "tries", options.Retries+1, "failures", strings.Join(failures, "; "))
208+
return fmt.Errorf("request exceeded retry limits: %s", failures[len(failures)-1])
207209
}
208210

209211
func sendRequestStream[T streamable](client *Client, req *http.Request, retryOpts ...RetryOptions) (*streamReader[T], error) {
@@ -228,12 +230,10 @@ func sendRequestStream[T streamable](client *Client, req *http.Request, retryOpt
228230
bodyBytes, err = io.ReadAll(req.Body)
229231
_ = req.Body.Close()
230232
if err != nil {
231-
failures = append(failures, fmt.Sprintf("failed to read request body: %v", err))
232-
return nil, fmt.Errorf("failed to read request body: %v; failures: %v", err, strings.Join(failures, "; "))
233+
return nil, fmt.Errorf("failed to read request body: %v", err)
233234
}
234235
}
235236

236-
streamRetryLoop:
237237
for i := 0; i <= options.Retries; i++ {
238238

239239
// Reset body to the original request body
@@ -263,8 +263,9 @@ streamRetryLoop:
263263

264264
// exit on non-retriable status codes
265265
if !options.canRetry(resp.StatusCode) {
266-
failures = append(failures, fmt.Sprintf("exiting due to non-retriable error in try #%d/%d: %v", i+1, options.Retries+1, resp.StatusCode))
267-
return nil, fmt.Errorf("request failed on non-retriable error: %v", strings.Join(failures, "; "))
266+
failures = append(failures, fmt.Sprintf("exiting due to non-retriable error in try #%d/%d: %d %s", i+1, options.Retries+1, resp.StatusCode, resp.Status))
267+
slog.Error("sendRequestStream failed due to non-retriable statuscode", "code", resp.StatusCode, "status", resp.Status, "tries", i+1, "maxTries", options.Retries+1, "failures", strings.Join(failures, "; "))
268+
return nil, fmt.Errorf("request failed on non-retriable status-code: %d %s", resp.StatusCode, resp.Status)
268269
}
269270

270271
// exponential backoff
@@ -273,11 +274,14 @@ streamRetryLoop:
273274
select {
274275
case <-req.Context().Done():
275276
failures = append(failures, fmt.Sprintf("exiting due to canceled context after try #%d/%d: %v", i+1, options.Retries+1, req.Context().Err()))
276-
break streamRetryLoop
277+
slog.Error("sendRequestStream failed due to canceled context", "tries", i+1, "maxTries", options.Retries+1, "failures", strings.Join(failures, "; "))
278+
return nil, fmt.Errorf("request failed due to canceled context: %v", req.Context().Err())
277279
case <-time.After(delay + jitter):
278280
}
279281
}
280-
return nil, fmt.Errorf("request failed %d times: %v", options.Retries+1, strings.Join(failures, "; "))
282+
283+
slog.Error("sendRequestStream failed after exceeding retry limit", "tries", options.Retries+1, "failures", strings.Join(failures, "; "))
284+
return nil, fmt.Errorf("request exceeded retry limits: %s", failures[len(failures)-1])
281285
}
282286

283287
func (c *Client) setCommonHeaders(req *http.Request) {

0 commit comments

Comments
 (0)