github.com/argoproj/argo-cd@v1.8.7/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  // nolint:unparam
    20  func shouldRetry(counter int, r *http.Request, response *http.Response, err error) bool {
    21  	if counter <= 0 {
    22  		return false
    23  	}
    24  	if err != nil {
    25  		if apierrors.IsInternalError(err) || apierrors.IsTimeout(err) || apierrors.IsServerTimeout(err) ||
    26  			apierrors.IsTooManyRequests(err) || utilnet.IsProbableEOF(err) || utilnet.IsConnectionReset(err) {
    27  			return true
    28  		}
    29  	}
    30  	if response != nil && (response.StatusCode == 504 || response.StatusCode == 503) {
    31  		return true
    32  	}
    33  
    34  	return false
    35  }
    36  
    37  func (frt *failureRetryRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
    38  	resp, roundTimeErr := frt.roundTripper.RoundTrip(r)
    39  	counter := frt.failureRetryCount
    40  	for shouldRetry(counter, r, resp, roundTimeErr) {
    41  		log.Debug("failureRetryRoundTripper: ", r.URL.Path, " ", r.Method)
    42  		time.Sleep(time.Duration(frt.failureRetryPeriodMilliSeconds) * time.Millisecond)
    43  		resp, roundTimeErr = frt.roundTripper.RoundTrip(r)
    44  		counter--
    45  	}
    46  	return resp, roundTimeErr
    47  }
    48  
    49  // AddFailureRetryWrapper adds a transport wrapper which wraps a function call around each kubernetes request
    50  func AddFailureRetryWrapper(config *rest.Config, failureRetryCount int, failureRetryPeriodSeconds int) *rest.Config {
    51  	wrap := config.WrapTransport
    52  	config.WrapTransport = func(rt http.RoundTripper) http.RoundTripper {
    53  		if wrap != nil {
    54  			rt = wrap(rt)
    55  		}
    56  		return &failureRetryRoundTripper{
    57  			roundTripper:                   rt,
    58  			failureRetryCount:              failureRetryCount,
    59  			failureRetryPeriodMilliSeconds: failureRetryPeriodSeconds,
    60  		}
    61  	}
    62  	return config
    63  }