diff --git a/CHANGELOG.md b/CHANGELOG.md index 199c714cb..bff710844 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +* Marked as deprecated `retry.WithDoRetryOptions` and `retry.WithDoTxRetryOptions` * Added receiving first result set on construct `internal/table/scanner.NewStream()` * Added experimental package `metrics` with SDK metrics * Fixed redundant trace call for finished `database/sql` transactions diff --git a/SQL.md b/SQL.md index 47cdc7baf..cc3ebf0e4 100644 --- a/SQL.md +++ b/SQL.md @@ -270,7 +270,7 @@ err := retry.Do(context.TODO(), db, func(ctx context.Context, cc *sql.Conn) erro } ... return nil // good final of retry operation -}, retry.WithDoRetryOptions(retry.WithIdempotent(true))) +}, retry.WithIdempotent(true)) ``` @@ -296,9 +296,7 @@ err := retry.DoTx(context.TODO(), db, func(ctx context.Context, tx *sql.Tx) erro } ... return nil // good final of retry tx operation -}, retry.WithDoTxRetryOptions( - retry.WithIdempotent(true), -), retry.WithTxOptions(&sql.TxOptions{ +}, retry.WithIdempotent(true), retry.WithTxOptions(&sql.TxOptions{ Isolation: sql.LevelSnapshot, ReadOnly: true, })) @@ -568,7 +566,7 @@ err := retry.Do(context.TODO(), db, func(ctx context.Context, cc *sql.Conn) erro } ... return nil // good final of retry operation -}, retry.WithDoRetryOptions(retry.WithIdempotent(true))) +}, retry.WithIdempotent(true)) ``` ## Troubleshooting diff --git a/example_test.go b/example_test.go index b74388874..542a6571a 100644 --- a/example_test.go +++ b/example_test.go @@ -86,7 +86,7 @@ func Example_databaseSQL() { } log.Printf("id=%v, myStr='%s'\n", id, myStr) return nil - }, retry.WithDoTxRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) if err != nil { log.Printf("query failed: %v", err) } diff --git a/examples/basic/database_sql/series.go b/examples/basic/database_sql/series.go index 68f726a96..2e4304f2d 100644 --- a/examples/basic/database_sql/series.go +++ b/examples/basic/database_sql/series.go @@ -9,7 +9,6 @@ import ( "path" "time" - "github.com/ydb-platform/ydb-go-sdk/v3" "github.com/ydb-platform/ydb-go-sdk/v3/retry" "github.com/ydb-platform/ydb-go-sdk/v3/sugar" "github.com/ydb-platform/ydb-go-sdk/v3/table" @@ -31,7 +30,7 @@ func selectDefault(ctx context.Context, db *sql.DB) (err error) { } log.Printf("AST = %s\n\nPlan = %s", ast, plan) return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) if err != nil { return fmt.Errorf("explain query failed: %w", err) } @@ -62,7 +61,7 @@ func selectDefault(ctx context.Context, db *sql.DB) (err error) { ) } return rows.Err() - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) if err != nil { return fmt.Errorf("execute data query failed: %w", err) } @@ -155,7 +154,7 @@ func selectScan(ctx context.Context, db *sql.DB) (err error) { ) } return rows.Err() - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) if err != nil { return fmt.Errorf("scan query failed: %w", err) } @@ -202,7 +201,7 @@ func fillTablesWithData(ctx context.Context, db *sql.DB) (err error) { return err } return nil - }, retry.WithDoTxRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) if err != nil { return fmt.Errorf("upsert query failed: %w", err) } @@ -235,7 +234,7 @@ func prepareSchema(ctx context.Context, db *sql.DB) (err error) { return err } return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) if err != nil { return fmt.Errorf("create table failed: %w", err) } @@ -266,7 +265,7 @@ func prepareSchema(ctx context.Context, db *sql.DB) (err error) { return err } return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) if err != nil { return fmt.Errorf("create table failed: %w", err) } @@ -299,7 +298,7 @@ func prepareSchema(ctx context.Context, db *sql.DB) (err error) { return err } return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) if err != nil { return fmt.Errorf("create table failed: %w", err) } diff --git a/internal/table/client.go b/internal/table/client.go index 044f7291a..63c2b5102 100644 --- a/internal/table/client.go +++ b/internal/table/client.go @@ -241,9 +241,7 @@ func (c *Client) CreateSession(ctx context.Context, opts ...table.Option) (_ tab } return s, nil } - options := retryOptions(c.config.Trace(), opts...) - err = retry.Retry( - ctx, + err = retry.Retry(ctx, func(ctx context.Context) (err error) { s, err = createSession(ctx) if err != nil { @@ -251,21 +249,23 @@ func (c *Client) CreateSession(ctx context.Context, opts ...table.Option) (_ tab } return nil }, - retry.WithIdempotent(true), - retry.WithID("CreateSession"), - retry.WithFastBackoff(options.FastBackoff), - retry.WithSlowBackoff(options.SlowBackoff), - retry.WithTrace(trace.Retry{ - OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { - onIntermediate := trace.TableOnCreateSession(c.config.Trace(), info.Context) - return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { - onDone := onIntermediate(info.Error) - return func(info trace.RetryLoopDoneInfo) { - onDone(s, info.Attempts, info.Error) - } - } - }, - }), + append( + []retry.Option{ + retry.WithIdempotent(true), + retry.WithID("CreateSession"), + retry.WithTrace(trace.Retry{ + OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { + onIntermediate := trace.TableOnCreateSession(c.config.Trace(), info.Context) + return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { + onDone := onIntermediate(info.Error) + return func(info trace.RetryLoopDoneInfo) { + onDone(s, info.Attempts, info.Error) + } + } + }, + }), + }, retryOptions(c.config.Trace(), opts...).RetryOptions..., + )..., ) if err != nil { return nil, xerrors.WithStackTrace(err) diff --git a/internal/table/retry.go b/internal/table/retry.go index 2efe5e5f6..f5ad6f93a 100644 --- a/internal/table/retry.go +++ b/internal/table/retry.go @@ -3,7 +3,6 @@ package table import ( "context" - "github.com/ydb-platform/ydb-go-sdk/v3/internal/backoff" "github.com/ydb-platform/ydb-go-sdk/v3/internal/table/config" "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors" "github.com/ydb-platform/ydb-go-sdk/v3/retry" @@ -50,18 +49,14 @@ func doTx( attempts, onIntermediate := 0, trace.TableOnDoTx( opts.Trace, &ctx, + opts.ID, opts.Idempotent, isRetryCalledAbove(ctx), ) defer func() { onIntermediate(err)(attempts, err) }() - err = retryBackoff( - ctx, - c, - opts.FastBackoff, - opts.SlowBackoff, - opts.Idempotent, + err = retryBackoff(ctx, c, func(ctx context.Context, s table.Session) (err error) { attempts++ @@ -110,6 +105,7 @@ func doTx( return nil }, + opts.RetryOptions..., ) if err != nil { return xerrors.WithStackTrace(err) @@ -127,11 +123,11 @@ func do( if opts.Trace == nil { opts.Trace = &trace.Table{} } - attempts, onIntermediate := 0, trace.TableOnDo(opts.Trace, &ctx, opts.Idempotent, isRetryCalledAbove(ctx)) + attempts, onIntermediate := 0, trace.TableOnDo(opts.Trace, &ctx, opts.ID, opts.Idempotent, isRetryCalledAbove(ctx)) defer func() { onIntermediate(err)(attempts, err) }() - return retryBackoff(ctx, c, opts.FastBackoff, opts.SlowBackoff, opts.Idempotent, + return retryBackoff(ctx, c, func(ctx context.Context, s table.Session) (err error) { attempts++ @@ -156,16 +152,15 @@ func do( return nil }, + opts.RetryOptions..., ) } func retryBackoff( ctx context.Context, p SessionProvider, - fastBackoff backoff.Backoff, - slowBackoff backoff.Backoff, - isOperationIdempotent bool, op table.Operation, + opts ...retry.Option, ) (err error) { err = retry.Retry(markRetryCall(ctx), func(ctx context.Context) (err error) { @@ -188,9 +183,7 @@ func retryBackoff( return nil }, - retry.WithFastBackoff(fastBackoff), - retry.WithSlowBackoff(slowBackoff), - retry.WithIdempotent(isOperationIdempotent), + opts..., ) if err != nil { return xerrors.WithStackTrace(err) @@ -200,9 +193,7 @@ func retryBackoff( func retryOptions(trace *trace.Table, opts ...table.Option) *table.Options { options := &table.Options{ - Trace: trace, - FastBackoff: backoff.Fast, - SlowBackoff: backoff.Slow, + Trace: trace, TxSettings: table.TxSettings( table.WithSerializableReadWrite(), ), diff --git a/internal/table/retry_test.go b/internal/table/retry_test.go index 1497f0f52..3e3897b81 100644 --- a/internal/table/retry_test.go +++ b/internal/table/retry_test.go @@ -49,16 +49,22 @@ func TestRetryerBackoffRetryCancelation(t *testing.T) { return testErr }, &table.Options{ - FastBackoff: testutil.BackoffFunc(func(n int) <-chan time.Time { - ch := make(chan time.Time) - backoff <- ch - return ch - }), - SlowBackoff: testutil.BackoffFunc(func(n int) <-chan time.Time { - ch := make(chan time.Time) - backoff <- ch - return ch - }), + RetryOptions: []retry.Option{ + retry.WithFastBackoff( + testutil.BackoffFunc(func(n int) <-chan time.Time { + ch := make(chan time.Time) + backoff <- ch + return ch + }), + ), + retry.WithSlowBackoff( + testutil.BackoffFunc(func(n int) <-chan time.Time { + ch := make(chan time.Time) + backoff <- ch + return ch + }), + ), + }, }, ) results <- err @@ -207,12 +213,18 @@ func TestRetryerImmediateReturn(t *testing.T) { return testErr }, &table.Options{ - FastBackoff: testutil.BackoffFunc(func(n int) <-chan time.Time { - panic("this code will not be called") - }), - SlowBackoff: testutil.BackoffFunc(func(n int) <-chan time.Time { - panic("this code will not be called") - }), + RetryOptions: []retry.Option{ + retry.WithFastBackoff( + testutil.BackoffFunc(func(n int) <-chan time.Time { + panic("this code will not be called") + }), + ), + retry.WithSlowBackoff( + testutil.BackoffFunc(func(n int) <-chan time.Time { + panic("this code will not be called") + }), + ), + }, }, ) if !xerrors.Is(err, testErr) { diff --git a/metrics/table.go b/metrics/table.go index 3875a8b21..961bcabcf 100644 --- a/metrics/table.go +++ b/metrics/table.go @@ -17,10 +17,14 @@ func table(config Config) (t trace.Table) { wait := config.WithSystem("pool").GaugeVec("wait") waitLatency := config.WithSystem("pool").WithSystem("wait").TimerVec("latency") alive := config.GaugeVec("sessions", "node_id") - doAttempts := config.WithSystem("do").HistogramVec("attempts", []float64{0, 1, 2, 5, 10}) - doErrors := config.WithSystem("do").WithSystem("intermediate").CounterVec("errors", "status") - doTxAttempts := config.WithSystem("doTx").HistogramVec("attempts", []float64{0, 1, 2, 5, 10}) - doTxErrors := config.WithSystem("doTx").WithSystem("intermediate").CounterVec("errors", "status") + doAttempts := config.WithSystem("do").HistogramVec("attempts", []float64{0, 1, 2, 5, 10}, "name") + doErrors := config.WithSystem("do").CounterVec("errors", "status", "name") + doIntermediateErrors := config.WithSystem("do").WithSystem("intermediate").CounterVec("errors", "status", "name") + doLatency := config.WithSystem("do").TimerVec("latency", "status", "name") + doTxAttempts := config.WithSystem("doTx").HistogramVec("attempts", []float64{0, 1, 2, 5, 10}, "name") + doTxIntermediateErrors := config.WithSystem("doTx").WithSystem("intermediate").CounterVec("errors", "status", "name") + doTxErrors := config.WithSystem("doTx").CounterVec("errors", "status", "name") + doTxLatency := config.WithSystem("doTx").TimerVec("latency", "status", "name") t.OnInit = func(info trace.TableInitStartInfo) func(trace.TableInitDoneInfo) { return func(info trace.TableInitDoneInfo) { limit.With(nil).Set(float64(info.Limit)) @@ -31,15 +35,28 @@ func table(config Config) (t trace.Table) { ) func( trace.TableDoDoneInfo, ) { + var ( + name = info.ID + start = time.Now() + ) return func(info trace.TableDoIntermediateInfo) func(trace.TableDoDoneInfo) { if info.Error != nil && config.Details()&trace.TableEvents != 0 { - doErrors.With(map[string]string{ + doIntermediateErrors.With(map[string]string{ "status": errorBrief(info.Error), + "name": name, }).Inc() } return func(info trace.TableDoDoneInfo) { if config.Details()&trace.TableEvents != 0 { doAttempts.With(nil).Record(float64(info.Attempts)) + doErrors.With(map[string]string{ + "status": errorBrief(info.Error), + "name": name, + }).Inc() + doLatency.With(map[string]string{ + "status": errorBrief(info.Error), + "name": name, + }).Record(time.Since(start)) } } } @@ -49,15 +66,28 @@ func table(config Config) (t trace.Table) { ) func( trace.TableDoTxDoneInfo, ) { + var ( + name = info.ID + start = time.Now() + ) return func(info trace.TableDoTxIntermediateInfo) func(trace.TableDoTxDoneInfo) { if info.Error != nil && config.Details()&trace.TableEvents != 0 { - doTxErrors.With(map[string]string{ + doTxIntermediateErrors.With(map[string]string{ "status": errorBrief(info.Error), + "name": name, }).Inc() } return func(info trace.TableDoTxDoneInfo) { if config.Details()&trace.TableEvents != 0 { doTxAttempts.With(nil).Record(float64(info.Attempts)) + doTxErrors.With(map[string]string{ + "status": errorBrief(info.Error), + "name": name, + }).Inc() + doTxLatency.With(map[string]string{ + "status": errorBrief(info.Error), + "name": name, + }).Record(time.Since(start)) } } } diff --git a/retry/retry.go b/retry/retry.go index 84ae006dc..2c2589a07 100644 --- a/retry/retry.go +++ b/retry/retry.go @@ -27,14 +27,22 @@ type retryOptions struct { panicCallback func(e interface{}) } -type retryOption interface { +type Option interface { ApplyRetryOption(opts *retryOptions) } -var _ retryOption = idOption("") +var _ Option = idOption("") type idOption string +func (id idOption) ApplyDoOption(opts *doOptions) { + opts.retryOptions = append(opts.retryOptions, WithID(string(id))) +} + +func (id idOption) ApplyDoTxOption(opts *doTxOptions) { + opts.retryOptions = append(opts.retryOptions, WithID(string(id))) +} + func (id idOption) ApplyRetryOption(opts *retryOptions) { opts.id = string(id) } @@ -44,20 +52,28 @@ func WithID(id string) idOption { return idOption(id) } -var _ retryOption = stackTraceOption{} +var _ Option = stackTraceOption{} type stackTraceOption struct{} -func (stackTrace stackTraceOption) ApplyRetryOption(opts *retryOptions) { +func (stackTraceOption) ApplyRetryOption(opts *retryOptions) { opts.stackTrace = true } +func (stackTraceOption) ApplyDoOption(opts *doOptions) { + opts.retryOptions = append(opts.retryOptions, WithStackTrace()) +} + +func (stackTraceOption) ApplyDoTxOption(opts *doTxOptions) { + opts.retryOptions = append(opts.retryOptions, WithStackTrace()) +} + // WithStackTrace wraps errors with stacktrace from Retry call func WithStackTrace() stackTraceOption { return stackTraceOption{} } -var _ retryOption = traceOption{} +var _ Option = traceOption{} type traceOption struct { trace *trace.Retry @@ -67,12 +83,20 @@ func (t traceOption) ApplyRetryOption(opts *retryOptions) { opts.trace = t.trace } +func (t traceOption) ApplyDoOption(opts *doOptions) { + opts.retryOptions = append(opts.retryOptions, WithTrace(*t.trace)) +} + +func (t traceOption) ApplyDoTxOption(opts *doTxOptions) { + opts.retryOptions = append(opts.retryOptions, WithTrace(*t.trace)) +} + // WithTrace returns trace option func WithTrace(trace trace.Retry) traceOption { return traceOption{trace: &trace} } -var _ retryOption = idempotentOption(false) +var _ Option = idempotentOption(false) type idempotentOption bool @@ -80,12 +104,20 @@ func (idempotent idempotentOption) ApplyRetryOption(opts *retryOptions) { opts.idempotent = bool(idempotent) } +func (idempotent idempotentOption) ApplyDoOption(opts *doOptions) { + opts.retryOptions = append(opts.retryOptions, WithIdempotent(bool(idempotent))) +} + +func (idempotent idempotentOption) ApplyDoTxOption(opts *doTxOptions) { + opts.retryOptions = append(opts.retryOptions, WithIdempotent(bool(idempotent))) +} + // WithIdempotent applies idempotent flag to retry operation func WithIdempotent(idempotent bool) idempotentOption { return idempotentOption(idempotent) } -var _ retryOption = fastBackoffOption{} +var _ Option = fastBackoffOption{} type fastBackoffOption struct { backoff backoff.Backoff @@ -97,12 +129,20 @@ func (o fastBackoffOption) ApplyRetryOption(opts *retryOptions) { } } +func (o fastBackoffOption) ApplyDoOption(opts *doOptions) { + opts.retryOptions = append(opts.retryOptions, WithFastBackoff(o.backoff)) +} + +func (o fastBackoffOption) ApplyDoTxOption(opts *doTxOptions) { + opts.retryOptions = append(opts.retryOptions, WithFastBackoff(o.backoff)) +} + // WithFastBackoff replaces default fast backoff func WithFastBackoff(b backoff.Backoff) fastBackoffOption { return fastBackoffOption{backoff: b} } -var _ retryOption = slowBackoffOption{} +var _ Option = slowBackoffOption{} type slowBackoffOption struct { backoff backoff.Backoff @@ -114,12 +154,20 @@ func (o slowBackoffOption) ApplyRetryOption(opts *retryOptions) { } } +func (o slowBackoffOption) ApplyDoOption(opts *doOptions) { + opts.retryOptions = append(opts.retryOptions, WithSlowBackoff(o.backoff)) +} + +func (o slowBackoffOption) ApplyDoTxOption(opts *doTxOptions) { + opts.retryOptions = append(opts.retryOptions, WithSlowBackoff(o.backoff)) +} + // WithSlowBackoff replaces default slow backoff func WithSlowBackoff(b backoff.Backoff) slowBackoffOption { return slowBackoffOption{backoff: b} } -var _ retryOption = panicCallbackOption{} +var _ Option = panicCallbackOption{} type panicCallbackOption struct { callback func(e interface{}) @@ -129,6 +177,14 @@ func (o panicCallbackOption) ApplyRetryOption(opts *retryOptions) { opts.panicCallback = o.callback } +func (o panicCallbackOption) ApplyDoOption(opts *doOptions) { + opts.retryOptions = append(opts.retryOptions, WithPanicCallback(o.callback)) +} + +func (o panicCallbackOption) ApplyDoTxOption(opts *doTxOptions) { + opts.retryOptions = append(opts.retryOptions, WithPanicCallback(o.callback)) +} + // WithPanicCallback returns panic callback option // If not defined - panic would not intercept with driver func WithPanicCallback(panicCallback func(e interface{})) panicCallbackOption { @@ -161,7 +217,7 @@ func isRetryCalledAbove(ctx context.Context) bool { // Warning: if deadline without deadline or cancellation func Retry will be worked infinite // // If you need to retry your op func on some logic errors - you must return RetryableError() from retryOperation -func Retry(ctx context.Context, op retryOperation, opts ...retryOption) (err error) { +func Retry(ctx context.Context, op retryOperation, opts ...Option) (err error) { options := &retryOptions{ fastBackoff: backoff.Fast, slowBackoff: backoff.Slow, diff --git a/retry/sql.go b/retry/sql.go index 19da67962..f6e6dd3c9 100644 --- a/retry/sql.go +++ b/retry/sql.go @@ -9,18 +9,29 @@ import ( ) type doOptions struct { - retryOptions []retryOption + retryOptions []Option } // doTxOption defines option for redefine default Retry behavior -type doOption func(o *doOptions) error +type doOption interface { + ApplyDoOption(opts *doOptions) +} + +var ( + _ doOption = doRetryOptionsOption(nil) + _ doOption = idOption("") +) + +type doRetryOptionsOption []Option + +func (retryOptions doRetryOptionsOption) ApplyDoOption(opts *doOptions) { + opts.retryOptions = append(opts.retryOptions, retryOptions...) +} // WithDoRetryOptions specified retry options -func WithDoRetryOptions(opts ...retryOption) doOption { - return func(o *doOptions) error { - o.retryOptions = append(o.retryOptions, opts...) - return nil - } +// Deprecated: use implicit options instead +func WithDoRetryOptions(opts ...Option) doRetryOptionsOption { + return opts } // Do is a retryer of database/sql Conn with fallbacks on errors @@ -29,11 +40,9 @@ func Do(ctx context.Context, db *sql.DB, f func(ctx context.Context, cc *sql.Con options = doOptions{} attempts = 0 ) - for _, o := range opts { - if o != nil { - if err := o(&options); err != nil { - return xerrors.WithStackTrace(err) - } + for _, opt := range opts { + if opt != nil { + opt.ApplyDoOption(&options) } } err := Retry(ctx, func(ctx context.Context) (err error) { @@ -60,25 +69,42 @@ func Do(ctx context.Context, db *sql.DB, f func(ctx context.Context, cc *sql.Con type doTxOptions struct { txOptions *sql.TxOptions - retryOptions []retryOption + retryOptions []Option } // doTxOption defines option for redefine default Retry behavior -type doTxOption func(o *doTxOptions) error +type doTxOption interface { + ApplyDoTxOption(o *doTxOptions) +} + +var _ doTxOption = doTxRetryOptionsOption(nil) + +type doTxRetryOptionsOption []Option + +func (doTxRetryOptions doTxRetryOptionsOption) ApplyDoTxOption(o *doTxOptions) { + o.retryOptions = append(o.retryOptions, doTxRetryOptions...) +} // WithDoTxRetryOptions specified retry options -func WithDoTxRetryOptions(opts ...retryOption) doTxOption { - return func(o *doTxOptions) error { - o.retryOptions = append(o.retryOptions, opts...) - return nil - } +// Deprecated: use implicit options instead +func WithDoTxRetryOptions(opts ...Option) doTxRetryOptionsOption { + return opts +} + +var _ doTxOption = txOptionsOption{} + +type txOptionsOption struct { + txOptions *sql.TxOptions +} + +func (txOptions txOptionsOption) ApplyDoTxOption(o *doTxOptions) { + o.txOptions = txOptions.txOptions } // WithTxOptions specified transaction options -func WithTxOptions(txOptions *sql.TxOptions) doTxOption { - return func(o *doTxOptions) error { - o.txOptions = txOptions - return nil +func WithTxOptions(txOptions *sql.TxOptions) txOptionsOption { + return txOptionsOption{ + txOptions: txOptions, } } @@ -93,11 +119,9 @@ func DoTx(ctx context.Context, db *sql.DB, f func(context.Context, *sql.Tx) erro } attempts = 0 ) - for _, o := range opts { - if o != nil { - if err := o(&options); err != nil { - return xerrors.WithStackTrace(err) - } + for _, opt := range opts { + if opt != nil { + opt.ApplyDoTxOption(&options) } } err := Retry(ctx, func(ctx context.Context) (err error) { diff --git a/retry/sql_test.go b/retry/sql_test.go index d7a88d6cf..2b968fb33 100644 --- a/retry/sql_test.go +++ b/retry/sql_test.go @@ -181,17 +181,18 @@ func TestDoTx(t *testing.T) { } db := sql.OpenDB(m) var attempts int - err := DoTx(context.Background(), db, func(ctx context.Context, tx *sql.Tx) error { - attempts++ - if attempts > 10 { - return nil - } - rows, err := tx.QueryContext(ctx, "SELECT 1") - if err != nil { - return err - } - return rows.Err() - }, WithDoTxRetryOptions( + err := DoTx(context.Background(), db, + func(ctx context.Context, tx *sql.Tx) error { + attempts++ + if attempts > 10 { + return nil + } + rows, err := tx.QueryContext(ctx, "SELECT 1") + if err != nil { + return err + } + return rows.Err() + }, WithIdempotent(bool(idempotentType)), WithFastBackoff(backoff.New(backoff.WithSlotDuration(time.Nanosecond))), WithSlowBackoff(backoff.New(backoff.WithSlotDuration(time.Nanosecond))), @@ -205,7 +206,7 @@ func TestDoTx(t *testing.T) { } }, }), - )) + ) if tt.canRetry[idempotentType] { if err != nil { t.Errorf("unexpected err after attempts=%d and driver conns=%d: %v)", attempts, m.conns, err) diff --git a/table/table.go b/table/table.go index 9ffc5fcd4..f6eabda65 100644 --- a/table/table.go +++ b/table/table.go @@ -9,9 +9,9 @@ import ( "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Table" "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator" - "github.com/ydb-platform/ydb-go-sdk/v3/internal/backoff" "github.com/ydb-platform/ydb-go-sdk/v3/internal/closer" "github.com/ydb-platform/ydb-go-sdk/v3/internal/value" + "github.com/ydb-platform/ydb-go-sdk/v3/retry" "github.com/ydb-platform/ydb-go-sdk/v3/table/options" "github.com/ydb-platform/ydb-go-sdk/v3/table/result" "github.com/ydb-platform/ydb-go-sdk/v3/table/types" @@ -559,11 +559,11 @@ func ValueParam(name string, v types.Value) ParameterOption { } type Options struct { + ID string Idempotent bool TxSettings *TransactionSettings TxCommitOptions []options.CommitTransactionOption - FastBackoff backoff.Backoff - SlowBackoff backoff.Backoff + RetryOptions []retry.Option Trace *trace.Table } @@ -571,12 +571,38 @@ type Option interface { ApplyTableOption(opts *Options) } +var _ Option = idOption("") + +type idOption string + +func (id idOption) ApplyTableOption(opts *Options) { + opts.ID = string(id) + opts.RetryOptions = append(opts.RetryOptions, retry.WithID(string(id))) +} + +func WithID(id string) idOption { + return idOption(id) +} + +var _ Option = retryOptionsOption{} + +type retryOptionsOption []retry.Option + +func (retryOptions retryOptionsOption) ApplyTableOption(opts *Options) { + opts.RetryOptions = append(opts.RetryOptions, retry.WithIdempotent(true)) +} + +func WithRetryOptions(retryOptions []retry.Option) retryOptionsOption { + return retryOptions +} + var _ Option = idempotentOption{} type idempotentOption struct{} func (idempotentOption) ApplyTableOption(opts *Options) { opts.Idempotent = true + opts.RetryOptions = append(opts.RetryOptions, retry.WithIdempotent(true)) } func WithIdempotent() idempotentOption { diff --git a/tests/integration/database_sql_containers_test.go b/tests/integration/database_sql_containers_test.go index a4bb04957..61b102db7 100644 --- a/tests/integration/database_sql_containers_test.go +++ b/tests/integration/database_sql_containers_test.go @@ -117,7 +117,7 @@ func TestDatabaseSqlContainers(t *testing.T) { } } return rows.Err() - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) } diff --git a/tests/integration/database_sql_get_column_type_test.go b/tests/integration/database_sql_get_column_type_test.go index d35657601..055333938 100644 --- a/tests/integration/database_sql_get_column_type_test.go +++ b/tests/integration/database_sql_get_column_type_test.go @@ -48,7 +48,7 @@ func TestDatabaseSqlGetColumnType(t *testing.T) { ) return err - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) @@ -119,7 +119,7 @@ func TestDatabaseSqlGetColumnType(t *testing.T) { require.ElementsMatch(t, columns, result) return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) @@ -176,7 +176,7 @@ func TestDatabaseSqlColumnTypes(t *testing.T) { } return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) diff --git a/tests/integration/database_sql_get_columns_test.go b/tests/integration/database_sql_get_columns_test.go index d4c9a51f3..06da4bc8e 100644 --- a/tests/integration/database_sql_get_columns_test.go +++ b/tests/integration/database_sql_get_columns_test.go @@ -45,7 +45,7 @@ func TestDatabaseSqlGetColumns(t *testing.T) { ) return err - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) @@ -74,7 +74,7 @@ func TestDatabaseSqlGetColumns(t *testing.T) { []string{"series_id", "season_id", "episode_id", "title", "air_date", "views"}, columns) return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) diff --git a/tests/integration/database_sql_get_index_columns_test.go b/tests/integration/database_sql_get_index_columns_test.go index 25e51fbb5..ac0bee009 100644 --- a/tests/integration/database_sql_get_index_columns_test.go +++ b/tests/integration/database_sql_get_index_columns_test.go @@ -49,7 +49,7 @@ func TestDatabaseSqlGetIndexColumns(t *testing.T) { } return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) @@ -91,7 +91,7 @@ func TestDatabaseSqlGetIndexColumns(t *testing.T) { test.IndexedColumns, columns) return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) } diff --git a/tests/integration/database_sql_get_indexes_test.go b/tests/integration/database_sql_get_indexes_test.go index c7fc092ee..dee61bbde 100644 --- a/tests/integration/database_sql_get_indexes_test.go +++ b/tests/integration/database_sql_get_indexes_test.go @@ -49,7 +49,7 @@ func TestDatabaseSqlGetIndexes(t *testing.T) { } return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) @@ -78,7 +78,7 @@ func TestDatabaseSqlGetIndexes(t *testing.T) { []string{"index_series_title", "index_seasons_aired_date"}, indexes) return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) diff --git a/tests/integration/database_sql_get_primary_keys_test.go b/tests/integration/database_sql_get_primary_keys_test.go index 4b49679f9..7c62a8158 100644 --- a/tests/integration/database_sql_get_primary_keys_test.go +++ b/tests/integration/database_sql_get_primary_keys_test.go @@ -45,7 +45,7 @@ func TestDatabaseSqlGetPrimaryKeys(t *testing.T) { ) return err - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) @@ -74,7 +74,7 @@ func TestDatabaseSqlGetPrimaryKeys(t *testing.T) { []string{"series_id", "season_id", "episode_id"}, pkCols) return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) diff --git a/tests/integration/database_sql_get_tables_test.go b/tests/integration/database_sql_get_tables_test.go index 70a9bc6bf..f5ae2b868 100644 --- a/tests/integration/database_sql_get_tables_test.go +++ b/tests/integration/database_sql_get_tables_test.go @@ -99,7 +99,7 @@ func TestDatabaseSqlGetTables(t *testing.T) { } return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) @@ -128,7 +128,7 @@ func TestDatabaseSqlGetTables(t *testing.T) { []string{"episodes", "series"}, tables) return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) @@ -157,7 +157,7 @@ func TestDatabaseSqlGetTables(t *testing.T) { []string{"seasons"}, tables) return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) @@ -186,7 +186,7 @@ func TestDatabaseSqlGetTables(t *testing.T) { []string{"seasons"}, tables) return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) @@ -273,7 +273,7 @@ func TestDatabaseSqlGetTablesRecursive(t *testing.T) { } return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) @@ -304,7 +304,7 @@ func TestDatabaseSqlGetTablesRecursive(t *testing.T) { []string{"episodes", "series", "subdir/seasons"}, tables) return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) @@ -335,7 +335,7 @@ func TestDatabaseSqlGetTablesRecursive(t *testing.T) { []string{"seasons"}, tables) return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) @@ -366,7 +366,7 @@ func TestDatabaseSqlGetTablesRecursive(t *testing.T) { []string{"seasons"}, tables) return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) diff --git a/tests/integration/database_sql_is_column_exists_test.go b/tests/integration/database_sql_is_column_exists_test.go index f54a67f4d..a10f94693 100644 --- a/tests/integration/database_sql_is_column_exists_test.go +++ b/tests/integration/database_sql_is_column_exists_test.go @@ -43,7 +43,7 @@ func TestDatabaseSqlIsColumnExists(t *testing.T) { ) return err - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) @@ -72,7 +72,7 @@ func TestDatabaseSqlIsColumnExists(t *testing.T) { require.True(t, exists) } return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) diff --git a/tests/integration/database_sql_is_primary_key_test.go b/tests/integration/database_sql_is_primary_key_test.go index 0c59234ba..2e9ee8133 100644 --- a/tests/integration/database_sql_is_primary_key_test.go +++ b/tests/integration/database_sql_is_primary_key_test.go @@ -45,7 +45,7 @@ func TestDatabaseSqlIsPrimaryKey(t *testing.T) { ) return err - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) @@ -74,7 +74,7 @@ func TestDatabaseSqlIsPrimaryKey(t *testing.T) { require.True(t, isPk) } return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) @@ -103,7 +103,7 @@ func TestDatabaseSqlIsPrimaryKey(t *testing.T) { require.False(t, isPk) } return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) diff --git a/tests/integration/database_sql_is_table_exists_test.go b/tests/integration/database_sql_is_table_exists_test.go index a786e2883..7bdb30f1c 100644 --- a/tests/integration/database_sql_is_table_exists_test.go +++ b/tests/integration/database_sql_is_table_exists_test.go @@ -52,7 +52,7 @@ func TestDatabaseSqlIsTableExists(t *testing.T) { } return err - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) @@ -75,7 +75,7 @@ func TestDatabaseSqlIsTableExists(t *testing.T) { ) return err - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) @@ -102,7 +102,7 @@ func TestDatabaseSqlIsTableExists(t *testing.T) { require.True(t, exists) return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) diff --git a/tests/integration/database_sql_regression_test.go b/tests/integration/database_sql_regression_test.go index 48f038b2c..9abacdfb2 100644 --- a/tests/integration/database_sql_regression_test.go +++ b/tests/integration/database_sql_regression_test.go @@ -67,9 +67,7 @@ func TestRegressionCloud109307(t *testing.T) { }, retry.WithTxOptions(&sql.TxOptions{ Isolation: sql.LevelSnapshot, ReadOnly: true, - }), retry.WithDoTxRetryOptions( - retry.WithIdempotent(true), - )) + }), retry.WithIdempotent(true)) if ctx.Err() == nil { require.NoError(t, err) } @@ -101,7 +99,7 @@ func TestRegressionKikimr17104(t *testing.T) { return err } return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true)), + }, retry.WithIdempotent(true), ) require.NoError(t, err) }) @@ -128,7 +126,7 @@ func TestRegressionKikimr17104(t *testing.T) { return err } return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true)), + }, retry.WithIdempotent(true), ) require.NoError(t, err) }) @@ -160,7 +158,7 @@ func TestRegressionKikimr17104(t *testing.T) { } } return rows.Err() - }, retry.WithDoRetryOptions(retry.WithIdempotent(true)), + }, retry.WithIdempotent(true), ) require.NoError(t, err) require.Equal(t, upsertRowsCount, rowsCount) diff --git a/tests/integration/database_sql_test.go b/tests/integration/database_sql_test.go index 3557b0356..42a7a71b3 100644 --- a/tests/integration/database_sql_test.go +++ b/tests/integration/database_sql_test.go @@ -178,7 +178,7 @@ func TestDatabaseSql(t *testing.T) { return fmt.Errorf("cannot upsert views: %w", err) } return nil - }, retry.WithDoTxRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) require.NoError(t, err) }) }) @@ -211,7 +211,7 @@ func TestDatabaseSql(t *testing.T) { } return nil }, - retry.WithDoTxRetryOptions(retry.WithIdempotent(true)), + retry.WithIdempotent(true), retry.WithTxOptions(&sql.TxOptions{ Isolation: sql.LevelSnapshot, ReadOnly: true, @@ -279,7 +279,7 @@ func TestDatabaseSql(t *testing.T) { } return rows.Err() }, - retry.WithDoTxRetryOptions(retry.WithIdempotent(true)), + retry.WithIdempotent(true), retry.WithTxOptions(&sql.TxOptions{Isolation: sql.LevelSnapshot, ReadOnly: true}), ) if !errors.Is(err, context.DeadlineExceeded) { @@ -467,7 +467,7 @@ func (s *sqlScope) fill(ctx context.Context) error { return fmt.Errorf("failed to execute statement: %w", err) } return nil - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) } func (s *sqlScope) createTables(ctx context.Context) error { diff --git a/tests/integration/table_truncated_err_test.go b/tests/integration/table_truncated_err_test.go index a35cd29f2..605475e00 100644 --- a/tests/integration/table_truncated_err_test.go +++ b/tests/integration/table_truncated_err_test.go @@ -83,7 +83,7 @@ func TestIssue798TruncatedError(t *testing.T) { return fmt.Errorf("unexpected rows count: %d", count) } return rows.Err() - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) scope.Require.NoError(err) } @@ -132,7 +132,7 @@ func TestIssue798TruncatedError(t *testing.T) { count++ } return rows.Err() - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) scope.Require.ErrorIs(err, result.ErrTruncated) } @@ -197,7 +197,7 @@ func TestIssue798TruncatedError(t *testing.T) { count++ } return rows.Err() - }, retry.WithDoRetryOptions(retry.WithIdempotent(true))) + }, retry.WithIdempotent(true)) scope.Require.NoError(err) } } diff --git a/tests/slo/database/sql/storage.go b/tests/slo/database/sql/storage.go index 380b45844..665be622a 100755 --- a/tests/slo/database/sql/storage.go +++ b/tests/slo/database/sql/storage.go @@ -4,10 +4,10 @@ import ( "context" "database/sql" "fmt" + ydb "github.com/ydb-platform/gorm-driver" "path" "time" - "github.com/ydb-platform/ydb-go-sdk/v3" "github.com/ydb-platform/ydb-go-sdk/v3/retry" "github.com/ydb-platform/ydb-go-sdk/v3/table" "github.com/ydb-platform/ydb-go-sdk/v3/trace" @@ -135,19 +135,17 @@ func (s *Storage) Read(ctx context.Context, entryID generator.RowID) (res genera return row.Scan(&res.ID, &res.PayloadStr, &res.PayloadDouble, &res.PayloadTimestamp, &hash) }, - retry.WithDoRetryOptions( - retry.WithIdempotent(true), - retry.WithTrace( - trace.Retry{ - OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { - return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { - return func(info trace.RetryLoopDoneInfo) { - attempts = info.Attempts - } + retry.WithIdempotent(true), + retry.WithTrace( + trace.Retry{ + OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { + return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { + return func(info trace.RetryLoopDoneInfo) { + attempts = info.Attempts } - }, + } }, - ), + }, ), ) @@ -177,19 +175,17 @@ func (s *Storage) Write(ctx context.Context, e generator.Row) (attempts int, err return err }, - retry.WithDoRetryOptions( - retry.WithIdempotent(true), - retry.WithTrace( - trace.Retry{ - OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { - return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { - return func(info trace.RetryLoopDoneInfo) { - attempts = info.Attempts - } + retry.WithIdempotent(true), + retry.WithTrace( + trace.Retry{ + OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { + return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { + return func(info trace.RetryLoopDoneInfo) { + attempts = info.Attempts } - }, + } }, - ), + }, ), ) @@ -208,7 +204,7 @@ func (s *Storage) createTable(ctx context.Context) error { func(ctx context.Context, cc *sql.Conn) error { _, err := s.db.ExecContext(ydb.WithQueryMode(ctx, ydb.SchemeQueryMode), s.createQuery) return err - }, retry.WithDoRetryOptions(retry.WithIdempotent(true)), + }, retry.WithIdempotent(true), ) } @@ -224,7 +220,7 @@ func (s *Storage) dropTable(ctx context.Context) error { func(ctx context.Context, cc *sql.Conn) error { _, err := s.db.ExecContext(ydb.WithQueryMode(ctx, ydb.SchemeQueryMode), s.dropQuery) return err - }, retry.WithDoRetryOptions(retry.WithIdempotent(true)), + }, retry.WithIdempotent(true), ) } diff --git a/tests/slo/gorm/storage.go b/tests/slo/gorm/storage.go index 7d6084f50..2b12dad37 100644 --- a/tests/slo/gorm/storage.go +++ b/tests/slo/gorm/storage.go @@ -107,19 +107,17 @@ func (s *Storage) Read(ctx context.Context, id generator.RowID) (r generator.Row return nil }, - retry.WithDoRetryOptions( - retry.WithIdempotent(true), - retry.WithTrace( - trace.Retry{ - OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { - return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { - return func(info trace.RetryLoopDoneInfo) { - attempts = info.Attempts - } + retry.WithIdempotent(true), + retry.WithTrace( + trace.Retry{ + OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { + return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { + return func(info trace.RetryLoopDoneInfo) { + attempts = info.Attempts } - }, + } }, - ), + }, ), ) @@ -157,19 +155,17 @@ func (s *Storage) Write(ctx context.Context, row generator.Row) (attempts int, e "PayloadTimestamp": row.PayloadTimestamp, }).Error }, - retry.WithDoRetryOptions( - retry.WithIdempotent(true), - retry.WithTrace( - trace.Retry{ - OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { - return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { - return func(info trace.RetryLoopDoneInfo) { - attempts = info.Attempts - } + retry.WithIdempotent(true), + retry.WithTrace( + trace.Retry{ + OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { + return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { + return func(info trace.RetryLoopDoneInfo) { + attempts = info.Attempts } - }, + } }, - ), + }, ), ) diff --git a/tests/slo/xorm/storage.go b/tests/slo/xorm/storage.go index 9a828dd3b..800f9f814 100644 --- a/tests/slo/xorm/storage.go +++ b/tests/slo/xorm/storage.go @@ -9,7 +9,6 @@ import ( "strconv" "time" - "github.com/ydb-platform/ydb-go-sdk/v3" "github.com/ydb-platform/ydb-go-sdk/v3/retry" "github.com/ydb-platform/ydb-go-sdk/v3/table" "github.com/ydb-platform/ydb-go-sdk/v3/trace" @@ -138,19 +137,17 @@ func (s *Storage) Read(ctx context.Context, id generator.RowID) (row generator.R return nil }, - retry.WithDoRetryOptions( - retry.WithIdempotent(true), - retry.WithTrace( - trace.Retry{ - OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { - return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { - return func(info trace.RetryLoopDoneInfo) { - attempts = info.Attempts - } + retry.WithIdempotent(true), + retry.WithTrace( + trace.Retry{ + OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { + return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { + return func(info trace.RetryLoopDoneInfo) { + attempts = info.Attempts } - }, + } }, - ), + }, ), ) @@ -174,19 +171,17 @@ func (s *Storage) Write(ctx context.Context, row generator.Row) (attempts int, e _, err = s.x.Context(ctx).SetExpr("hash", fmt.Sprintf("Digest::NumericHash(%d)", row.ID)).Insert(row) return err }, - retry.WithDoRetryOptions( - retry.WithIdempotent(true), - retry.WithTrace( - trace.Retry{ - OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { - return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { - return func(info trace.RetryLoopDoneInfo) { - attempts = info.Attempts - } + retry.WithIdempotent(true), + retry.WithTrace( + trace.Retry{ + OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { + return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) { + return func(info trace.RetryLoopDoneInfo) { + attempts = info.Attempts } - }, + } }, - ), + }, ), ) diff --git a/trace/table.go b/trace/table.go index d799fb393..8fd59d2a1 100644 --- a/trace/table.go +++ b/trace/table.go @@ -379,6 +379,7 @@ type ( // Warning: concurrent access to pointer on client side must be excluded. // Safe replacement of context are provided only inside callback function Context *context.Context + ID string Idempotent bool NestedCall bool // flag when Retry called inside head Retry } @@ -395,6 +396,7 @@ type ( // Warning: concurrent access to pointer on client side must be excluded. // Safe replacement of context are provided only inside callback function Context *context.Context + ID string Idempotent bool NestedCall bool // flag when Retry called inside head Retry } diff --git a/trace/table_gtrace.go b/trace/table_gtrace.go index 78cf39049..706859753 100644 --- a/trace/table_gtrace.go +++ b/trace/table_gtrace.go @@ -1420,9 +1420,10 @@ func TableOnClose(t *Table, c *context.Context) func(error) { res(p) } } -func TableOnDo(t *Table, c *context.Context, idempotent bool, nestedCall bool) func(error) func(attempts int, _ error) { +func TableOnDo(t *Table, c *context.Context, iD string, idempotent bool, nestedCall bool) func(error) func(attempts int, _ error) { var p TableDoStartInfo p.Context = c + p.ID = iD p.Idempotent = idempotent p.NestedCall = nestedCall res := t.onDo(p) @@ -1438,9 +1439,10 @@ func TableOnDo(t *Table, c *context.Context, idempotent bool, nestedCall bool) f } } } -func TableOnDoTx(t *Table, c *context.Context, idempotent bool, nestedCall bool) func(error) func(attempts int, _ error) { +func TableOnDoTx(t *Table, c *context.Context, iD string, idempotent bool, nestedCall bool) func(error) func(attempts int, _ error) { var p TableDoTxStartInfo p.Context = c + p.ID = iD p.Idempotent = idempotent p.NestedCall = nestedCall res := t.onDoTx(p)