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

     1  package table
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/closer"
     7  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/pool"
     8  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/table/config"
     9  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
    10  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
    11  	"github.com/ydb-platform/ydb-go-sdk/v3/retry"
    12  	"github.com/ydb-platform/ydb-go-sdk/v3/table"
    13  	"github.com/ydb-platform/ydb-go-sdk/v3/trace"
    14  )
    15  
    16  // sessionPool is the interface that holds session lifecycle logic.
    17  type sessionPool interface {
    18  	closer.Closer
    19  
    20  	Stats() pool.Stats
    21  	With(ctx context.Context, f func(ctx context.Context, s *session) error, opts ...retry.Option) error
    22  }
    23  
    24  func do(
    25  	ctx context.Context,
    26  	pool sessionPool,
    27  	config *config.Config,
    28  	op table.Operation,
    29  	onAttempt func(err error),
    30  	opts ...retry.Option,
    31  ) (err error) {
    32  	return retryBackoff(ctx, pool,
    33  		func(ctx context.Context, s table.Session) (err error) {
    34  			defer func() {
    35  				if onAttempt != nil {
    36  					onAttempt(err)
    37  				}
    38  			}()
    39  
    40  			err = func() error {
    41  				if panicCallback := config.PanicCallback(); panicCallback != nil {
    42  					defer func() {
    43  						if e := recover(); e != nil {
    44  							panicCallback(e)
    45  						}
    46  					}()
    47  				}
    48  
    49  				return op(xcontext.MarkRetryCall(ctx), s)
    50  			}()
    51  			if err != nil {
    52  				return xerrors.WithStackTrace(err)
    53  			}
    54  
    55  			return nil
    56  		},
    57  		opts...,
    58  	)
    59  }
    60  
    61  func retryBackoff(
    62  	ctx context.Context,
    63  	pool sessionPool,
    64  	op table.Operation,
    65  	opts ...retry.Option,
    66  ) error {
    67  	return pool.With(ctx, func(ctx context.Context, s *session) error {
    68  		if err := op(ctx, s); err != nil {
    69  			s.checkError(err)
    70  
    71  			return xerrors.WithStackTrace(err)
    72  		}
    73  
    74  		return nil
    75  	}, opts...)
    76  }
    77  
    78  func (c *Client) retryOptions(opts ...table.Option) *table.Options {
    79  	options := &table.Options{
    80  		Trace: c.config.Trace(),
    81  		TxSettings: table.TxSettings(
    82  			table.WithSerializableReadWrite(),
    83  		),
    84  		RetryOptions: []retry.Option{
    85  			retry.WithTrace(c.config.TraceRetry()),
    86  			retry.WithBudget(c.config.RetryBudget()),
    87  		},
    88  	}
    89  	for _, opt := range opts {
    90  		if opt != nil {
    91  			opt.ApplyTableOption(options)
    92  		}
    93  	}
    94  	if options.Trace == nil {
    95  		options.Trace = &trace.Table{}
    96  	}
    97  
    98  	return options
    99  }