github.com/ydb-platform/ydb-go-sdk/v3@v3.57.0/internal/topic/retriable_error.go (about)

     1  package topic
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io"
     7  	"time"
     8  
     9  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/backoff"
    10  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
    11  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
    12  	"github.com/ydb-platform/ydb-go-sdk/v3/retry"
    13  )
    14  
    15  const (
    16  	DefaultStartTimeout          = time.Minute
    17  	connectionEstablishedTimeout = time.Minute
    18  )
    19  
    20  type RetrySettings struct {
    21  	StartTimeout time.Duration // Full retry timeout
    22  	CheckError   PublicCheckErrorRetryFunction
    23  }
    24  
    25  type PublicCheckErrorRetryFunction func(errInfo PublicCheckErrorRetryArgs) PublicCheckRetryResult
    26  
    27  type PublicCheckErrorRetryArgs struct {
    28  	Error error
    29  }
    30  
    31  func NewCheckRetryArgs(err error) PublicCheckErrorRetryArgs {
    32  	return PublicCheckErrorRetryArgs{
    33  		Error: err,
    34  	}
    35  }
    36  
    37  type PublicCheckRetryResult struct {
    38  	val int
    39  }
    40  
    41  var (
    42  	PublicRetryDecisionDefault = PublicCheckRetryResult{val: 0}
    43  	PublicRetryDecisionRetry   = PublicCheckRetryResult{val: 1}
    44  	PublicRetryDecisionStop    = PublicCheckRetryResult{val: 2}
    45  )
    46  
    47  func CheckResetReconnectionCounters(lastTry, now time.Time, connectionTimeout time.Duration) bool {
    48  	const resetAttemptEmpiricalCoefficient = 10
    49  	if connectionTimeout == value.InfiniteDuration {
    50  		return now.Sub(lastTry) > connectionEstablishedTimeout
    51  	}
    52  
    53  	return now.Sub(lastTry) > connectionTimeout*resetAttemptEmpiricalCoefficient
    54  }
    55  
    56  func CheckRetryMode(err error, settings RetrySettings, retriesDuration time.Duration) (
    57  	_ backoff.Backoff,
    58  	isRetriable bool,
    59  ) {
    60  	// nil is not error and doesn't need retry it.
    61  	if err == nil {
    62  		return nil, false
    63  	}
    64  
    65  	// eof is retriable for topic
    66  	if errors.Is(err, io.EOF) && xerrors.RetryableError(err) == nil {
    67  		err = xerrors.Retryable(err, xerrors.WithName("TopicEOF"))
    68  	}
    69  
    70  	if retriesDuration > settings.StartTimeout {
    71  		return nil, false
    72  	}
    73  
    74  	mode := retry.Check(err)
    75  
    76  	decision := PublicRetryDecisionDefault
    77  	if settings.CheckError != nil {
    78  		decision = settings.CheckError(NewCheckRetryArgs(err))
    79  	}
    80  
    81  	switch decision {
    82  	case PublicRetryDecisionDefault:
    83  		isRetriable = mode.MustRetry(true)
    84  	case PublicRetryDecisionRetry:
    85  		isRetriable = true
    86  	case PublicRetryDecisionStop:
    87  		isRetriable = false
    88  	default:
    89  		panic(fmt.Errorf("unexpected retry decision: %v", decision))
    90  	}
    91  
    92  	if !isRetriable {
    93  		return nil, false
    94  	}
    95  
    96  	switch mode.BackoffType() {
    97  	case backoff.TypeFast:
    98  		return backoff.Fast, true
    99  	default:
   100  		return backoff.Slow, true
   101  	}
   102  }