github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/pkg/retry/retry.go (about) 1 package retry 2 3 import ( 4 "fmt" 5 "net/http" 6 "time" 7 8 "github.com/avast/retry-go/v4" 9 "github.com/pkg/errors" 10 ) 11 12 // ExecutableHTTPFunc defines a generic HTTP function to be executed 13 type ExecutableHTTPFunc func() (*http.Response, error) 14 15 // Config configuration for the HTTPExecutor 16 type Config struct { 17 Attempts uint `envconfig:"APP_HTTP_RETRY_ATTEMPTS"` 18 Delay time.Duration `envconfig:"APP_HTTP_RETRY_DELAY"` 19 } 20 21 // HTTPExecutor is capable of executing HTTP requests with a leveraged retry mechanism for more resilience 22 type HTTPExecutor struct { 23 attempts uint 24 delay time.Duration 25 acceptableStatusCodes []int 26 } 27 28 // NewHTTPExecutor constructs an HTTPExecutor based on the provided Config 29 func NewHTTPExecutor(config *Config) *HTTPExecutor { 30 return &HTTPExecutor{ 31 attempts: config.Attempts, 32 delay: config.Delay, 33 acceptableStatusCodes: []int{http.StatusOK}, 34 } 35 } 36 37 // WithAcceptableStatusCodes allows overriding the default acceptableStatusCodes values 38 func (he *HTTPExecutor) WithAcceptableStatusCodes(statusCodes []int) { 39 he.acceptableStatusCodes = statusCodes 40 } 41 42 // Execute wraps the provided ExecutableHTTPFunc with a retry mechanism and executes it 43 func (he *HTTPExecutor) Execute(doRequest ExecutableHTTPFunc) (*http.Response, error) { 44 var resp *http.Response 45 var err error 46 err = retry.Do(func() error { 47 resp, err = doRequest() 48 if err != nil { 49 return err 50 } 51 52 for _, code := range he.acceptableStatusCodes { 53 if resp.StatusCode == code { 54 return nil 55 } 56 } 57 58 return errors.New(fmt.Sprintf("unexpected status code: %d", resp.StatusCode)) 59 }, retry.Attempts(he.attempts), retry.Delay(he.delay)) 60 61 return resp, err 62 }