github.com/argoproj/argo-cd/v3@v3.2.1/util/kube/failureretrywrapper.go (about)

     1  package kube
     2  
     3  import (
     4  	"net/http"
     5  	"time"
     6  
     7  	log "github.com/sirupsen/logrus"
     8  	apierrors "k8s.io/apimachinery/pkg/api/errors"
     9  	utilnet "k8s.io/apimachinery/pkg/util/net"
    10  	"k8s.io/client-go/rest"
    11  )
    12  
    13  type failureRetryRoundTripper struct {
    14  	roundTripper                   http.RoundTripper
    15  	failureRetryCount              int
    16  	failureRetryPeriodMilliSeconds int
    17  }
    18  
    19  func shouldRetry(counter int, _ *http.Request, response *http.Response, err error) bool {
    20  	if counter <= 0 {
    21  		return false
    22  	}
    23  	if err != nil {
    24  		if apierrors.IsInternalError(err) || apierrors.IsTimeout(err) || apierrors.IsServerTimeout(err) ||
    25  			apierrors.IsTooManyRequests(err) || utilnet.IsProbableEOF(err) || utilnet.IsConnectionReset(err) {
    26  			return true
    27  		}
    28  	}
    29  	if response != nil && (response.StatusCode == http.StatusGatewayTimeout || response.StatusCode == http.StatusServiceUnavailable) {
    30  		return true
    31  	}
    32  
    33  	return false
    34  }
    35  
    36  func (frt *failureRetryRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
    37  	resp, roundTimeErr := frt.roundTripper.RoundTrip(r)
    38  	counter := frt.failureRetryCount
    39  	for shouldRetry(counter, r, resp, roundTimeErr) {
    40  		log.Debug("failureRetryRoundTripper: ", r.URL.Path, " ", r.Method)
    41  		time.Sleep(time.Duration(frt.failureRetryPeriodMilliSeconds) * time.Millisecond)
    42  		resp, roundTimeErr = frt.roundTripper.RoundTrip(r)
    43  		counter--
    44  	}
    45  	return resp, roundTimeErr
    46  }
    47  
    48  // AddFailureRetryWrapper adds a transport wrapper which wraps a function call around each kubernetes request
    49  func AddFailureRetryWrapper(config *rest.Config, failureRetryCount int, failureRetryPeriodSeconds int) *rest.Config {
    50  	wrap := config.WrapTransport
    51  	config.WrapTransport = func(rt http.RoundTripper) http.RoundTripper {
    52  		if wrap != nil {
    53  			rt = wrap(rt)
    54  		}
    55  		return &failureRetryRoundTripper{
    56  			roundTripper:                   rt,
    57  			failureRetryCount:              failureRetryCount,
    58  			failureRetryPeriodMilliSeconds: failureRetryPeriodSeconds,
    59  		}
    60  	}
    61  	return config
    62  }