hashicorp / hashicorp/go-retryablehttp
Return last not nil response on context Canceled/DeadlineExceeded errors
- 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.