Skip to content

Commit

Permalink
add retry client
Browse files Browse the repository at this point in the history
  • Loading branch information
mahesh-hpe committed Nov 25, 2024
1 parent 79858d7 commit 5d4cef0
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 16 deletions.
13 changes: 6 additions & 7 deletions internal/acceptance_test/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"context"
"fmt"
"log"
"net/http"
"os"
"strconv"
"time"
Expand Down Expand Up @@ -58,16 +57,16 @@ func getAPIClient() (*api_client.APIClient, api_client.Configuration) {
if err != nil {
log.Printf("[ERROR] Error getting cmp details: %s", err)
}
tr := &http.Transport{
MaxIdleConns: 20,
MaxIdleConnsPerHost: 20,
DisableKeepAlives: true,
}
// tr := &http.Transport{
// MaxIdleConns: 20,
// MaxIdleConnsPerHost: 20,
// DisableKeepAlives: true,
// }
cfg := api_client.Configuration{
Host: cmpDetails.URL,
DefaultHeader: map[string]string{},
DefaultQueryParams: map[string]string{},
HTTPClient: &http.Client{Transport: tr, Timeout: 2 * time.Minute},
HTTPClient: utils.NewRetryableClient(),
}
cmpAPIClient := api_client.NewAPIClient(&cfg)
cmpAPIClient.CMPToken = cmpDetails.AccessToken
Expand Down
16 changes: 7 additions & 9 deletions pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ package client

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

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"

Expand Down Expand Up @@ -74,16 +72,16 @@ func (i InitialiseClient) NewClient(r *schema.ResourceData) (interface{}, error)
brokerHeaders := getHeaders()
tenantID := r.Get(constants.TenantID).(string)
brokerHeaders["X-Tenant-ID"] = tenantID
tr := &http.Transport{
MaxIdleConns: 20,
MaxIdleConnsPerHost: 20,
DisableKeepAlives: true,
}
// tr := &http.Transport{
// MaxIdleConns: 20,
// MaxIdleConnsPerHost: 20,
// DisableKeepAlives: true,
// }
brokerCfgForAPIClient := api_client.Configuration{
Host: vmaasProviderSettings[constants.BROKERRURL].(string),
DefaultHeader: brokerHeaders,
DefaultQueryParams: queryParam,
HTTPClient: &http.Client{Transport: tr, Timeout: 2 * time.Minute},
HTTPClient: utils.NewRetryableClient(),
}
brokerApiClient := api_client.NewAPIClient(&brokerCfgForAPIClient)
utils.SetMetaFnAndVersion(brokerApiClient, r, 0)
Expand All @@ -92,7 +90,7 @@ func (i InitialiseClient) NewClient(r *schema.ResourceData) (interface{}, error)
Host: "",
DefaultHeader: map[string]string{},
DefaultQueryParams: map[string]string{},
HTTPClient: &http.Client{Transport: tr, Timeout: 2 * time.Minute},
HTTPClient: utils.NewRetryableClient(),
}
apiClient := api_client.NewAPIClient(&cfg)
err = utils.SetCMPVars(apiClient, brokerApiClient, &cfg)
Expand Down
87 changes: 87 additions & 0 deletions pkg/utils/http_retry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package utils

import (
"bytes"
"io"
"math"
"net/http"
"time"
)

const RetryCount = 3

type retryableTransport struct {
transport http.RoundTripper
}

func backoff(retries int) time.Duration {
return time.Duration(math.Pow(2, float64(retries))) * time.Second
}

func shouldRetry(err error, resp *http.Response) bool {
if err != nil {
return true
}

if resp.StatusCode == 401 {
return true
}

return false
}

func drainBody(resp *http.Response) {
if resp.Body != nil {
io.Copy(io.Discard, resp.Body)
resp.Body.Close()
}
}

func (t *retryableTransport) RoundTrip(req *http.Request) (*http.Response, error) {
// Clone the request body
var bodyBytes []byte
if req.Body != nil {
bodyBytes, _ = io.ReadAll(req.Body)
req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
}

// Send the request
resp, err := t.transport.RoundTrip(req)

// Retry logic
retries := 0
for shouldRetry(err, resp) && retries < RetryCount {
// Wait for the specified backoff period
time.Sleep(backoff(retries))

// We're going to retry, consume any response to reuse the connection.
drainBody(resp)

// Clone the request body again
if req.Body != nil {
req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
}

// Retry the request
resp, err = t.transport.RoundTrip(req)

retries++
}

// Return the response
return resp, err
}

func NewRetryableClient() *http.Client {
transport := &retryableTransport{
transport: &http.Transport{
MaxIdleConns: 20,
MaxIdleConnsPerHost: 20,
DisableKeepAlives: true},
}

return &http.Client{
Transport: transport,
Timeout: 2 * time.Minute,
}
}

0 comments on commit 5d4cef0

Please sign in to comment.