pkg/common/apiretry/apiretry.go (56 lines of code) (raw):

/* Copyright (c) Microsoft Corporation. Licensed under the MIT license. */ // Package apiretry provides the retry func shared between networking controllers. package apiretry import ( "context" "errors" "time" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/util/retry" ) // Do will retry the do func only when the error is transient. func Do(do func() error) error { backOffPeriod := retry.DefaultBackoff backOffPeriod.Cap = time.Second * 1 return retry.OnError(backOffPeriod, func(err error) bool { return retriable(err) }, do) } func retriable(err error) bool { if apierrors.IsTimeout(err) || apierrors.IsServerTimeout(err) || apierrors.IsTooManyRequests(err) { return true } return false } // WaitUntilObjectDeleted will ensure obj is deleted until it hits the backoff cap. // It will retry only when it gets the object or the error is transient. func WaitUntilObjectDeleted(ctx context.Context, get func() error) error { backOffPeriod := wait.Backoff{ Steps: 5, Duration: 500 * time.Millisecond, Factor: 1.6, Jitter: 0.2, } backOffPeriod.Cap = time.Second * 5 var lastErr error err := wait.ExponentialBackoffWithContext(ctx, backOffPeriod, func(_ context.Context) (bool, error) { err := get() switch { case err == nil: lastErr = err return false, nil case apierrors.IsNotFound(err): return true, nil case retriable(err): lastErr = err return false, nil default: return false, err } }) if wait.Interrupted(err) { if lastErr == nil { return wait.ErrorInterrupted(errors.New("timed out or the context ended")) } err = lastErr } return err }