hashicorp / hashicorp/go-retryablehttp

Retry after context cancel

Open
#167 2 comments 10 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
2.3k
Forks
298
PR merge metrics
No merged PRs in 30d

Description

Hello I have a use case where I'd like to impose a timeout on my http client with retries. This means that http client's context cancellation should be retryable action. According to my testing it is not:

```go
func TestRetryableHTTP(t *testing.T) {
client := retryablehttp.NewClient()
client.CheckRetry = func(ctx context.Context, resp *http.Response, err error) (bool, error) {
if ctx.Err() != nil {
return true, ctx.Err()
}
return retryablehttp.DefaultRetryPolicy(ctx, resp, err)
}

attempts := 0
handlerWithDelay := func(delay time.Duration) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
attempts++
ticker := time.NewTicker(delay)
select {
case <-r.Context().Done():
t.Log("connection droppped from client")
return
case <-ticker.C:
}
t.Log("responding 200 OK")
w.WriteHeader(http.StatusOK)
})
}
ts := httptest.NewServer(handlerWithDelay(10 * time.Second))
defer ts.Close()

ctx, cancelFn := context.WithTimeout(context.Background(), time.Second)
defer cancelFn()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, ts.URL, nil)
require.NoError(t, err)

retReq, err := retryablehttp.FromRequest(req)
require.NoError(t, err)
_, err = client.Do(retReq)
assert.NoError(t, err)

assert.Equal(t, 5, attempts) // 4 retries + first call

}
```
Test output:
```
=== RUN TestRetryableHTTP
2022/05/16 19:18:41 [DEBUG] GET http://127.0.0.1:49948
2022/05/16 19:18:42 [ERR] GET http://127.0.0.1:49948 request failed: Get "http://127.0.0.1:49948": context deadline exceeded
2022/05/16 19:18:42 [DEBUG] GET http://127.0.0.1:49948: retrying in 1s (4 left)
sanehttp_test.go:168: connection droppped from client
sanehttp_test.go:187:
Error Trace: sanehttp_test.go:187
Error: Received unexpected error:
context deadline exceeded
Test: TestRetryableHTTP
sanehttp_test.go:189:
Error Trace: sanehttp_test.go:189
Error: Not equal:
expected: 5
actual : 1
Test: TestRetryableHTTP
--- FAIL: TestRetryableHTTP (1.01s)
```

You can see there was only 1 attempt and no retries.

I have also tried to use the http client `Timeout` field instead of context cancellation but it yields the same result.

I was checking the source code and it looks like you are not retrying on errors from `client.Do()` which is the case. Do you know if there is a way how to make my use case work?

Thank you.

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.