github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/retry.go (about) 1 package cmd 2 3 import ( 4 "context" 5 "fmt" 6 "math/rand" 7 "time" 8 9 json "github.com/minio/colorjson" 10 "github.com/minio/mc/pkg/probe" 11 ) 12 13 type retryManager struct { 14 retries int 15 maxRetries int 16 retryInterval time.Duration 17 commandCtx context.Context 18 retryCtx context.Context 19 cancelRetry context.CancelFunc 20 } 21 22 func newRetryManager(ctx context.Context, retryInterval time.Duration, maxRetries int) *retryManager { 23 retryCtx, cancelFunc := context.WithCancel(context.Background()) 24 return &retryManager{ 25 retryInterval: retryInterval, 26 maxRetries: maxRetries, 27 commandCtx: ctx, 28 retryCtx: retryCtx, 29 cancelRetry: cancelFunc, 30 } 31 } 32 33 type retryMessage struct { 34 SourceURL string `json:"sourceURL"` 35 TargetURL string `json:"targetURL"` 36 Retries int `json:"retries"` 37 } 38 39 func (r retryMessage) String() string { 40 return fmt.Sprintf("<INFO> Retries %d: source `%s` >> target `%s`", r.Retries, r.SourceURL, r.TargetURL) 41 } 42 43 func (r retryMessage) JSON() string { 44 jsonMessageBytes, e := json.MarshalIndent(r, "", " ") 45 fatalIf(probe.NewError(e), "Unable to marshal into JSON.") 46 return string(jsonMessageBytes) 47 } 48 49 func (r *retryManager) retry(action func(rm *retryManager) *probe.Error) { 50 defer r.cancelRetry() 51 for r.retries <= r.maxRetries { 52 53 err := action(r) 54 if err == nil { 55 return 56 } 57 58 select { 59 case <-r.retryCtx.Done(): 60 return 61 case <-r.commandCtx.Done(): 62 return 63 case <-time.After(r.retryInterval/2 + time.Duration(rand.Int63n(int64(r.retryInterval)))): 64 r.retries++ 65 } 66 67 } 68 }