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

     1  package table
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/table/config"
     7  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
     8  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
     9  	"github.com/ydb-platform/ydb-go-sdk/v3/retry"
    10  	"github.com/ydb-platform/ydb-go-sdk/v3/table"
    11  	"github.com/ydb-platform/ydb-go-sdk/v3/trace"
    12  )
    13  
    14  // SessionProvider is the interface that holds session lifecycle logic.
    15  type SessionProvider interface {
    16  	// Get returns alive idle session or creates new one.
    17  	Get(ctx context.Context) (*session, error)
    18  
    19  	// Put takes no longer needed session for reuse or deletion depending
    20  	// on implementation.
    21  	// Put must be fast, if necessary must be async
    22  	Put(ctx context.Context, s *session) (err error)
    23  }
    24  
    25  func do(
    26  	ctx context.Context,
    27  	c SessionProvider,
    28  	config *config.Config,
    29  	op table.Operation,
    30  	onAttempt func(err error),
    31  	opts ...retry.Option,
    32  ) (err error) {
    33  	return retryBackoff(ctx, c,
    34  		func(ctx context.Context, s table.Session) (err error) {
    35  			defer func() {
    36  				if onAttempt != nil {
    37  					onAttempt(err)
    38  				}
    39  			}()
    40  
    41  			err = func() error {
    42  				if panicCallback := config.PanicCallback(); panicCallback != nil {
    43  					defer func() {
    44  						if e := recover(); e != nil {
    45  							panicCallback(e)
    46  						}
    47  					}()
    48  				}
    49  
    50  				return op(xcontext.MarkRetryCall(ctx), s)
    51  			}()
    52  
    53  			if err != nil {
    54  				return xerrors.WithStackTrace(err)
    55  			}
    56  
    57  			return nil
    58  		},
    59  		opts...,
    60  	)
    61  }
    62  
    63  func retryBackoff(
    64  	ctx context.Context,
    65  	p SessionProvider,
    66  	op table.Operation,
    67  	opts ...retry.Option,
    68  ) error {
    69  	return retry.Retry(ctx,
    70  		func(ctx context.Context) (err error) {
    71  			var s *session
    72  
    73  			s, err = p.Get(ctx)
    74  			if err != nil {
    75  				return xerrors.WithStackTrace(err)
    76  			}
    77  
    78  			defer func() {
    79  				_ = p.Put(ctx, s)
    80  			}()
    81  
    82  			if err = op(ctx, s); err != nil {
    83  				s.checkError(err)
    84  
    85  				return xerrors.WithStackTrace(err)
    86  			}
    87  
    88  			return nil
    89  		},
    90  		opts...,
    91  	)
    92  }
    93  
    94  func (c *Client) retryOptions(opts ...table.Option) *table.Options {
    95  	options := &table.Options{
    96  		Trace: c.config.Trace(),
    97  		TxSettings: table.TxSettings(
    98  			table.WithSerializableReadWrite(),
    99  		),
   100  		RetryOptions: []retry.Option{
   101  			retry.WithTrace(c.config.TraceRetry()),
   102  		},
   103  	}
   104  	for _, opt := range opts {
   105  		if opt != nil {
   106  			opt.ApplyTableOption(options)
   107  		}
   108  	}
   109  	if options.Trace == nil {
   110  		options.Trace = &trace.Table{}
   111  	}
   112  
   113  	return options
   114  }