| OLD | NEW |
| 1 // Copyright 2015 The LUCI Authors. All rights reserved. | 1 // Copyright 2015 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 package retry | 5 package retry |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "time" | 8 "time" |
| 9 | 9 |
| 10 "github.com/luci/luci-go/common/errors" | 10 "github.com/luci/luci-go/common/errors" |
| 11 "golang.org/x/net/context" | 11 "golang.org/x/net/context" |
| 12 ) | 12 ) |
| 13 | 13 |
| 14 // transientOnlyIterator is an Iterator implementation that only retries errors | 14 // transientOnlyIterator is an Iterator implementation that only retries errors |
| 15 // if they are transient. | 15 // if they are tagged with `retry.Tag`. |
| 16 // | |
| 17 // (See errors.IsTransient). | |
| 18 type transientOnlyIterator struct { | 16 type transientOnlyIterator struct { |
| 19 Iterator // The wrapped Iterator. | 17 Iterator // The wrapped Iterator. |
| 20 } | 18 } |
| 21 | 19 |
| 22 func (i *transientOnlyIterator) Next(ctx context.Context, err error) time.Durati
on { | 20 func (i *transientOnlyIterator) Next(ctx context.Context, err error) time.Durati
on { |
| 23 » if !errors.IsTransient(err) { | 21 » if !Tag.In(err) { |
| 24 return Stop | 22 return Stop |
| 25 } | 23 } |
| 26 return i.Iterator.Next(ctx, err) | 24 return i.Iterator.Next(ctx, err) |
| 27 } | 25 } |
| 28 | 26 |
| 29 // TransientOnly returns an Iterator that wraps another Iterator. It will fall | 27 // TransientOnly returns an Iterator that wraps another Iterator. It will fall |
| 30 // through to the wrapped Iterator if a transient error is encountered; | 28 // through to the wrapped Iterator if a transient error is encountered; |
| 31 // otherwise, it will not retry. | 29 // otherwise, it will not retry. |
| 32 // Returns nil if f is nil. | 30 // Returns nil if f is nil. |
| 33 func TransientOnly(f Factory) Factory { | 31 func TransientOnly(f Factory) Factory { |
| 34 if f == nil { | 32 if f == nil { |
| 35 return nil | 33 return nil |
| 36 } | 34 } |
| 37 return wrap(f, func(it Iterator) Iterator { | 35 return wrap(f, func(it Iterator) Iterator { |
| 38 return &transientOnlyIterator{it} | 36 return &transientOnlyIterator{it} |
| 39 }) | 37 }) |
| 40 } | 38 } |
| 39 |
| 40 // Tag is used to indicate that an error should be retried by this package. Use |
| 41 // like: |
| 42 // err = retry.Tag.Apply(err) |
| 43 // |
| 44 // This allows libraries to preserve the original error, but indicate to the |
| 45 // retry library that the error may be transient. |
| 46 var Tag = errors.NewBoolTag("this error may go away with a retry") |
| OLD | NEW |