|
- package retry
-
- import (
- "fmt"
- "gitlab.ecloud.com/ecloud/ecloudsdkcore/errs"
- "time"
- )
-
- type Template struct {
- RetryPolicy Policy
- RetryTimes int32
- MaxDuringTime int64
- }
-
- type RetryError struct {
- *errs.SdkError
- NumberOfFailedAttempts int32
- MaxDuringTimeOfFailedAttempts int64
- LastFailedRetryContext Context
- }
-
- func NewRetryError(numberOfFailedAttempts int32, maxDuringTimeOfFailedAttempts int64, lastFailedRetryContext Context) *RetryError {
- var msg string
- if numberOfFailedAttempts > 0 {
- msg = fmt.Sprintf("Retrying failed to complete successfully after %v attempts.", numberOfFailedAttempts)
- }
- if maxDuringTimeOfFailedAttempts > 0 {
- msg = fmt.Sprintf("Retrying failed to complete successfully after %v milliseconds.", maxDuringTimeOfFailedAttempts)
- }
- var retryErr error
- if v, err := lastFailedRetryContext.(*ErrorContext); err {
- retryErr = v.Err
- } else {
- retryErr = nil
- }
-
- return &RetryError{
- SdkError: errs.NewSdkError("RetryError", msg, retryErr),
- }
- }
-
- type ReFunc func() (interface{}, error)
-
- func (t *Template) Call(f ReFunc) (interface{}, error) {
- startTime := time.Now().UnixNano()
- for retryTimes := 1; ; retryTimes++ {
- var ctx Context
- res, err := f()
- duration := (time.Now().UnixNano() - startTime) / 1e6
- if err != nil {
- ctx = &ErrorContext{
- Err: err,
- RetryTimes: int32(retryTimes),
- DelayTime: duration,
- }
- } else {
- ctx = &ResultContext{
- Result: res,
- RetryTimes: int32(retryTimes),
- DelayTime: duration,
- }
- }
- if r, err := ctx.(*ResultContext); err {
- return r.Result, nil
- }
- if int32(retryTimes) == t.RetryTimes {
- return nil, NewRetryError(int32(retryTimes), 0, ctx)
- } else if duration >= t.MaxDuringTime {
- return nil, NewRetryError(int32(retryTimes), duration, ctx)
- } else {
- sleepTime := t.RetryPolicy.computeWaitTime(ctx)
- if sleepTime <= 0 {
- continue
- }
- time.Sleep(time.Duration(sleepTime * 1e6))
- }
- }
- }
|