Skip to content

Commit

Permalink
Merge pull request #131 from hashicorp/add-service-unavailable-to-def…
Browse files Browse the repository at this point in the history
…ault-backoff-retry-after

Add StatusServiceUnavailable to Retry-After check in DefaultBackoff
  • Loading branch information
vancluever committed Apr 27, 2021
2 parents 991b9d0 + 207df31 commit 02c1586
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 24 deletions.
2 changes: 1 addition & 1 deletion client.go
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ func baseRetryPolicy(resp *http.Response, err error) (bool, error) {
// seconds the server states it may be ready to process more requests from this client.
func DefaultBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration {
if resp != nil {
if resp.StatusCode == http.StatusTooManyRequests {
if resp.StatusCode == http.StatusTooManyRequests || resp.StatusCode == http.StatusServiceUnavailable {
if s, ok := resp.Header["Retry-After"]; ok {
if sleep, err := strconv.ParseInt(s[0], 10, 64); err == nil {
return time.Second * time.Duration(sleep)
Expand Down
50 changes: 27 additions & 23 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -523,35 +523,39 @@ func TestClient_CheckRetry(t *testing.T) {
}
}

func TestClient_DefaultBackoff429TooManyRequest(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Retry-After", "2")
http.Error(w, "test_429_body", http.StatusTooManyRequests)
}))
defer ts.Close()
func TestClient_DefaultBackoff(t *testing.T) {
for _, code := range []int{http.StatusTooManyRequests, http.StatusServiceUnavailable} {
t.Run(fmt.Sprintf("http_%d", code), func(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Retry-After", "2")
http.Error(w, fmt.Sprintf("test_%d_body", code), code)
}))
defer ts.Close()

client := NewClient()
client := NewClient()

var retryAfter time.Duration
retryable := false
var retryAfter time.Duration
retryable := false

client.CheckRetry = func(_ context.Context, resp *http.Response, err error) (bool, error) {
retryable, _ = DefaultRetryPolicy(context.Background(), resp, err)
retryAfter = DefaultBackoff(client.RetryWaitMin, client.RetryWaitMax, 1, resp)
return false, nil
}
client.CheckRetry = func(_ context.Context, resp *http.Response, err error) (bool, error) {
retryable, _ = DefaultRetryPolicy(context.Background(), resp, err)
retryAfter = DefaultBackoff(client.RetryWaitMin, client.RetryWaitMax, 1, resp)
return false, nil
}

_, err := client.Get(ts.URL)
if err != nil {
t.Fatalf("expected no errors since retryable")
}
_, err := client.Get(ts.URL)
if err != nil {
t.Fatalf("expected no errors since retryable")
}

if !retryable {
t.Fatal("Since 429 is recoverable, the default policy shall return true")
}
if !retryable {
t.Fatal("Since the error is recoverable, the default policy shall return true")
}

if retryAfter != 2*time.Second {
t.Fatalf("The header Retry-After specified 2 seconds, and shall not be %d seconds", retryAfter/time.Second)
if retryAfter != 2*time.Second {
t.Fatalf("The header Retry-After specified 2 seconds, and shall not be %d seconds", retryAfter/time.Second)
}
})
}
}

Expand Down

0 comments on commit 02c1586

Please sign in to comment.