@@ -257,10 +257,8 @@ func WithPanicCallback(panicCallback func(e interface{})) panicCallbackOption {
257257// Warning: if context without deadline or cancellation func was passed, Retry will work infinitely.
258258//
259259// # If you need to retry your op func on some logic errors - you must return RetryableError() from retryOperation
260- //
261- // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
262260func Retry (ctx context.Context , op retryOperation , opts ... Option ) (finalErr error ) {
263- _ , err := RetryWithResult [struct {}](ctx , func (ctx context.Context ) (* struct {}, error ) {
261+ _ , err := RetryWithResult [* struct {}](ctx , func (ctx context.Context ) (* struct {}, error ) {
264262 err := op (ctx )
265263 if err != nil {
266264 return nil , xerrors .WithStackTrace (err )
@@ -285,19 +283,22 @@ func Retry(ctx context.Context, op retryOperation, opts ...Option) (finalErr err
285283//
286284// Warning: if context without deadline or cancellation func was passed, RetryWithResult will work infinitely.
287285//
288- // If you need to retry your op func on some logic errors - you must return RetryableError() from retryOperation
286+ // # If you need to retry your op func on some logic errors - you must return RetryableError() from retryOperation
289287//
290- //nolint:funlen
291- func RetryWithResult [T any ](ctx context.Context , //nolint:revive
292- op func (context.Context ) (* T , error ), opts ... Option ,
293- ) (v * T , finalErr error ) {
294- options := & retryOptions {
295- call : stack .FunctionID ("github.com/ydb-platform/ydb-go-sdk/3/retry.RetryWithResult" ),
296- trace : & trace.Retry {},
297- budget : budget .Limited (- 1 ),
298- fastBackoff : backoff .Fast ,
299- slowBackoff : backoff .Slow ,
300- }
288+ // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
289+ func RetryWithResult [T any ](ctx context.Context , //nolint:revive,funlen
290+ op func (context.Context ) (T , error ), opts ... Option ,
291+ ) (_ T , finalErr error ) {
292+ var (
293+ zeroValue T
294+ options = & retryOptions {
295+ call : stack .FunctionID ("github.com/ydb-platform/ydb-go-sdk/3/retry.RetryWithResult" ),
296+ trace : & trace.Retry {},
297+ budget : budget .Limited (- 1 ),
298+ fastBackoff : backoff .Fast ,
299+ slowBackoff : backoff .Slow ,
300+ }
301+ )
301302 for _ , opt := range opts {
302303 if opt != nil {
303304 opt .ApplyRetryOption (options )
@@ -332,13 +333,12 @@ func RetryWithResult[T any](ctx context.Context, //nolint:revive
332333 attempts ++
333334 select {
334335 case <- ctx .Done ():
335- return nil , xerrors .WithStackTrace (
336+ return zeroValue , xerrors .WithStackTrace (
336337 fmt .Errorf ("retry failed on attempt No.%d: %w" , attempts , ctx .Err ()),
337338 )
338339
339340 default :
340- var err error
341- v , err = opWithRecover (ctx , options , op )
341+ v , err := opWithRecover (ctx , options , op )
342342
343343 if err == nil {
344344 return v , nil
@@ -353,7 +353,7 @@ func RetryWithResult[T any](ctx context.Context, //nolint:revive
353353 code = m .StatusCode ()
354354
355355 if ! m .MustRetry (options .idempotent ) {
356- return nil , xerrors .WithStackTrace (
356+ return zeroValue , xerrors .WithStackTrace (
357357 fmt .Errorf ("non-retryable error occurred on attempt No.%d (idempotent=%v): %w" ,
358358 attempts , options .idempotent , err ),
359359 )
@@ -368,7 +368,7 @@ func RetryWithResult[T any](ctx context.Context, //nolint:revive
368368 case <- ctx .Done ():
369369 t .Stop ()
370370
371- return nil , xerrors .WithStackTrace (
371+ return zeroValue , xerrors .WithStackTrace (
372372 xerrors .Join (
373373 fmt .Errorf ("attempt No.%d: %w" , attempts , ctx .Err ()),
374374 err ,
@@ -378,7 +378,7 @@ func RetryWithResult[T any](ctx context.Context, //nolint:revive
378378 t .Stop ()
379379
380380 if acquireErr := options .budget .Acquire (ctx ); acquireErr != nil {
381- return nil , xerrors .WithStackTrace (
381+ return zeroValue , xerrors .WithStackTrace (
382382 xerrors .Join (
383383 fmt .Errorf ("attempt No.%d: %w" , attempts , budget .ErrNoQuota ),
384384 acquireErr ,
@@ -392,20 +392,26 @@ func RetryWithResult[T any](ctx context.Context, //nolint:revive
392392}
393393
394394func opWithRecover [T any ](ctx context.Context ,
395- options * retryOptions , op func (context.Context ) (* T , error ),
396- ) (_ * T , err error ) {
395+ options * retryOptions , op func (context.Context ) (T , error ),
396+ ) (_ T , finalErr error ) {
397+ var zeroValue T
397398 if options .panicCallback != nil {
398399 defer func () {
399400 if e := recover (); e != nil {
400401 options .panicCallback (e )
401- err = xerrors .WithStackTrace (
402+ finalErr = xerrors .WithStackTrace (
402403 fmt .Errorf ("panic recovered: %v" , e ),
403404 )
404405 }
405406 }()
406407 }
407408
408- return op (ctx )
409+ v , err := op (ctx )
410+ if err != nil {
411+ return zeroValue , xerrors .WithStackTrace (err )
412+ }
413+
414+ return v , nil
409415}
410416
411417// Check returns retry mode for queryErr.
0 commit comments