github.com/jghiloni/cli@v6.28.1-0.20170628223758-0ce05fe032a2+incompatible/api/plugin/wrapper/retry_request.go (about)

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