1package httpclient 2 3import ( 4 "net/http" 5 "time" 6 7 "github.com/cloudfoundry/bosh-utils/errors" 8 boshlog "github.com/cloudfoundry/bosh-utils/logger" 9 boshretry "github.com/cloudfoundry/bosh-utils/retrystrategy" 10) 11 12type retryClient struct { 13 delegate Client 14 maxAttempts uint 15 retryDelay time.Duration 16 logger boshlog.Logger 17 isResponseAttemptable func(*http.Response, error) (bool, error) 18} 19 20func NewRetryClient( 21 delegate Client, 22 maxAttempts uint, 23 retryDelay time.Duration, 24 logger boshlog.Logger, 25) Client { 26 return &retryClient{ 27 delegate: delegate, 28 maxAttempts: maxAttempts, 29 retryDelay: retryDelay, 30 logger: logger, 31 isResponseAttemptable: nil, 32 } 33} 34 35func NewNetworkSafeRetryClient( 36 delegate Client, 37 maxAttempts uint, 38 retryDelay time.Duration, 39 logger boshlog.Logger, 40) Client { 41 return &retryClient{ 42 delegate: delegate, 43 maxAttempts: maxAttempts, 44 retryDelay: retryDelay, 45 logger: logger, 46 isResponseAttemptable: func(resp *http.Response, err error) (bool, error) { 47 if err != nil || ((resp.Request.Method == "GET" || resp.Request.Method == "HEAD") && (resp.StatusCode == http.StatusGatewayTimeout || resp.StatusCode == http.StatusServiceUnavailable || resp.StatusCode == http.StatusBadGateway)) { 48 return true, errors.WrapError(err, "Retry") 49 } 50 51 return false, nil 52 }, 53 } 54} 55 56func (r *retryClient) Do(req *http.Request) (*http.Response, error) { 57 requestRetryable := NewRequestRetryable(req, r.delegate, r.logger, r.isResponseAttemptable) 58 retryStrategy := boshretry.NewAttemptRetryStrategy(int(r.maxAttempts), r.retryDelay, requestRetryable, r.logger) 59 err := retryStrategy.Try() 60 61 return requestRetryable.Response(), err 62} 63