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 }