hashicorp / hashicorp/go-retryablehttp

Return last not nil response on context Canceled/DeadlineExceeded errors

Open
#129 1 comment 14 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
2.3k
Forks
298
PR merge metrics
No merged PRs in 30d

Description

I think it would be good to give the user access to last response on `.Do(req)` errors. That is assuming there was at least one request for which we got a response. As a user when a timeout or context cancellation happens I'd like to have access to last response because based on the response status code and body I can make certain decisions on how the error should be handled.

@ryanuber @jefferai are maintainers open to accepting this change?

Possible solutions (subjectively ranked by my preference):
1. `retrun lastNotNilResponse, err` from `.Do(req)` e.g. from this place https://github.com/hashicorp/go-retryablehttp/blob/991b9d0a42d13014e3689dd49a94c02be01f4237/client.go#L654
2. create custom error type that holds the error + last response and supports `errors.Is` etc. checks
3. provide a new ErrorHandler factory that returns an error handler like PassthroughErrorHandler. The created error handler would store not nil responses to a user defined variable that was passed to the factory when creating the ErrorHandler.
4. save lastResponse somewhere on the `retryablehttp.Client` object

Minimal working example with a comment explaining the change that I'd like to see:
```
package main

import (
"context"
"fmt"
"net/http"
"time"

"github.com/hashicorp/go-retryablehttp"
)

func main() {
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
go func() {
time.Sleep(time.Second * 5)
cancel()
}()
req, err := http.NewRequestWithContext(ctx, "GET", "https://httpstat.us/500", nil)
if err != nil {
panic(err)
}
retryReq, err := retryablehttp.FromRequest(req)
if err != nil {
panic(err)
}
retryableClient := retryablehttp.NewClient()
retryableClient.HTTPClient = &http.Client{Timeout: time.Second}
retryableClient.RetryMax = 10
retryableClient.ErrorHandler = retryablehttp.PassthroughErrorHandler

resp, err := retryableClient.Do(retryReq)
if err != nil {
if resp != nil {
// I'd like the program to enter this code block.
fmt.Println(resp.StatusCode)
} else {
fmt.Println("resp is nil")
}
fmt.Println(err)
return
}
fmt.Println(resp.StatusCode)
}

```

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.