github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/api/cloudcontroller/wrapper/retry_request.go (about)

     1  package wrapper
     2  
     3  import (
     4  	"net/http"
     5  
     6  	"code.cloudfoundry.org/cli/api/cloudcontroller"
     7  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
     8  )
     9  
    10  // RetryRequest is a wrapper that retries failed requests if they contain a 5XX
    11  // status code.
    12  type RetryRequest struct {
    13  	maxRetries int
    14  	connection cloudcontroller.Connection
    15  }
    16  
    17  // NewRetryRequest returns a pointer to a RetryRequest wrapper.
    18  func NewRetryRequest(maxRetries int) *RetryRequest {
    19  	return &RetryRequest{
    20  		maxRetries: maxRetries,
    21  	}
    22  }
    23  
    24  // Make retries the request if it comes back with a 5XX status code.
    25  func (retry *RetryRequest) Make(request *cloudcontroller.Request, passedResponse *cloudcontroller.Response) error {
    26  	var err error
    27  
    28  	for i := 0; i < retry.maxRetries+1; i++ {
    29  		err = retry.connection.Make(request, passedResponse)
    30  		if err == nil {
    31  			return nil
    32  		}
    33  
    34  		if retry.skipRetry(request.Method, passedResponse.HTTPResponse) {
    35  			break
    36  		}
    37  
    38  		// Reset the request body prior to the next retry
    39  		resetErr := request.ResetBody()
    40  		if resetErr != nil {
    41  			if _, ok := resetErr.(ccerror.PipeSeekError); ok {
    42  				return ccerror.PipeSeekError{Err: err}
    43  			}
    44  			return resetErr
    45  		}
    46  	}
    47  	return err
    48  }
    49  
    50  // Wrap sets the connection in the RetryRequest and returns itself.
    51  func (retry *RetryRequest) Wrap(innerconnection cloudcontroller.Connection) cloudcontroller.Connection {
    52  	retry.connection = innerconnection
    53  	return retry
    54  }
    55  
    56  // skipRetry will skip retry if the request method is POST or contains a status
    57  // code that is not one of following http status codes: 500, 502, 503, 504.
    58  func (*RetryRequest) skipRetry(httpMethod string, response *http.Response) bool {
    59  	return httpMethod == http.MethodPost ||
    60  		response != nil &&
    61  			response.StatusCode != http.StatusInternalServerError &&
    62  			response.StatusCode != http.StatusBadGateway &&
    63  			response.StatusCode != http.StatusServiceUnavailable &&
    64  			response.StatusCode != http.StatusGatewayTimeout
    65  }