mirror of
				https://github.com/containers/podman.git
				synced 2025-11-04 17:07:20 +08:00 
			
		
		
		
	Retry pulling image
Wrap the inner helper in the retry function. Functions pullimage failed with retriable error will default maxretry 3 times using exponential backoff. Signed-off-by: Qi Wang <qiwan@redhat.com>
This commit is contained in:
		
							
								
								
									
										87
									
								
								vendor/github.com/containers/common/pkg/retry/retry.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								vendor/github.com/containers/common/pkg/retry/retry.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,87 @@
 | 
			
		||||
package retry
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"math"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/distribution/registry/api/errcode"
 | 
			
		||||
	errcodev2 "github.com/docker/distribution/registry/api/v2"
 | 
			
		||||
	"github.com/hashicorp/go-multierror"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// RetryOptions defines the option to retry
 | 
			
		||||
type RetryOptions struct {
 | 
			
		||||
	MaxRetry int // The number of times to possibly retry
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RetryIfNecessary retries the operation in exponential backoff with the retryOptions
 | 
			
		||||
func RetryIfNecessary(ctx context.Context, operation func() error, retryOptions *RetryOptions) error {
 | 
			
		||||
	err := operation()
 | 
			
		||||
	for attempt := 0; err != nil && isRetryable(err) && attempt < retryOptions.MaxRetry; attempt++ {
 | 
			
		||||
		delay := time.Duration(int(math.Pow(2, float64(attempt)))) * time.Second
 | 
			
		||||
		logrus.Infof("Warning: failed, retrying in %s ... (%d/%d)", delay, attempt+1, retryOptions.MaxRetry)
 | 
			
		||||
		select {
 | 
			
		||||
		case <-time.After(delay):
 | 
			
		||||
			break
 | 
			
		||||
		case <-ctx.Done():
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		err = operation()
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isRetryable(err error) bool {
 | 
			
		||||
	err = errors.Cause(err)
 | 
			
		||||
 | 
			
		||||
	if err == context.Canceled || err == context.DeadlineExceeded {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	type unwrapper interface {
 | 
			
		||||
		Unwrap() error
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch e := err.(type) {
 | 
			
		||||
 | 
			
		||||
	case errcode.Error:
 | 
			
		||||
		switch e.Code {
 | 
			
		||||
		case errcode.ErrorCodeUnauthorized, errcodev2.ErrorCodeNameUnknown, errcodev2.ErrorCodeManifestUnknown:
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	case *net.OpError:
 | 
			
		||||
		return isRetryable(e.Err)
 | 
			
		||||
	case *url.Error:
 | 
			
		||||
		return isRetryable(e.Err)
 | 
			
		||||
	case syscall.Errno:
 | 
			
		||||
		return e != syscall.ECONNREFUSED
 | 
			
		||||
	case errcode.Errors:
 | 
			
		||||
		// if this error is a group of errors, process them all in turn
 | 
			
		||||
		for i := range e {
 | 
			
		||||
			if !isRetryable(e[i]) {
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	case *multierror.Error:
 | 
			
		||||
		// if this error is a group of errors, process them all in turn
 | 
			
		||||
		for i := range e.Errors {
 | 
			
		||||
			if !isRetryable(e.Errors[i]) {
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return true
 | 
			
		||||
	case unwrapper:
 | 
			
		||||
		err = e.Unwrap()
 | 
			
		||||
		return isRetryable(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user