Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions pkg/client/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ import (

"github.com/sirupsen/logrus"

"github.com/hashicorp/go-retryablehttp"
retryablehttp "github.com/hashicorp/go-retryablehttp"
"github.com/jetstack/version-checker/pkg/api"
"github.com/jetstack/version-checker/pkg/client/util"
)

const (
Expand Down Expand Up @@ -41,8 +42,10 @@ func New(opts Options, log *logrus.Entry) (*Client, error) {
}
retryclient.HTTPClient.Timeout = 10 * time.Second
retryclient.RetryMax = 10
retryclient.RetryWaitMax = 2 * time.Minute
retryclient.RetryWaitMax = 10 * time.Minute
retryclient.RetryWaitMin = 1 * time.Second
// This custom backoff will fail requests that have a max wait of the RetryWaitMax
retryclient.Backoff = util.HTTPBackOff
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably worth adding a note here that this could be removed if hashicorp/go-retryablehttp#247 is addressed.

retryclient.Logger = log.WithField("client", "docker")
client := retryclient.StandardClient()

Expand Down
19 changes: 19 additions & 0 deletions pkg/client/util/http_backoff.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package util

import (
"net/http"
"time"

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

// This is a custom Backoff that enforces the Max wait duration.
// If the sleep is greater we refuse to sleep at all
func HTTPBackOff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration {
sleep := retryablehttp.DefaultBackoff(min, max, attemptNum, resp)
if sleep.Abs() <= max {
return sleep.Abs()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor code legibility - this is backwards to how I'd normally read code. I'd normally expect the conditional to handle the exception case, here we're returning what I'd expect would be the normal mode of operation.

}

return max.Abs()
}
63 changes: 63 additions & 0 deletions pkg/client/util/http_backoff_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package util

import (
"net/http"
"testing"
"time"

"github.com/hashicorp/go-retryablehttp"
"github.com/stretchr/testify/assert"
)

func TestHTTPBackOff(t *testing.T) {
tests := []struct {
name string
min time.Duration
max time.Duration
attemptNum int
resp *http.Response
expSleep time.Duration
}{
{
name: "sleep within max duration",
min: 100 * time.Millisecond,
max: 1 * time.Second,
attemptNum: 1,
resp: nil,
expSleep: retryablehttp.DefaultBackoff(100*time.Millisecond, 1*time.Second, 1, nil),
},
{
name: "sleep exceeds max duration (too many requests)",
min: 100 * time.Millisecond,
max: 500 * time.Millisecond,
attemptNum: 10,
resp: &http.Response{
StatusCode: http.StatusTooManyRequests,
Header: http.Header{"Retry-After": []string{"3600"}}},
expSleep: 500 * time.Millisecond,
},
{
name: "zero max duration",
min: 100 * time.Millisecond,
max: 0,
attemptNum: 1,
resp: nil,
expSleep: 0,
},
{
name: "negative max duration",
min: 100 * time.Millisecond,
max: -1 * time.Second,
attemptNum: 1,
resp: nil,
expSleep: time.Second,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
gotSleep := HTTPBackOff(test.min, test.max, test.attemptNum, test.resp)
assert.Equal(t, test.expSleep, gotSleep, "unexpected sleep duration")
})
}
}
Loading