OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. |
| 4 |
| 5 // Package transient allows you to tag and retry 'transient' errors (i.e. |
| 6 // non-permanent errors which may resolve themselves by trying an operation |
| 7 // again). This should be used on errors due to network flake, improperly |
| 8 // responsive remote servers (e.g. status 500), unusual timeouts, etc. where |
| 9 // there's no concrete knowledge that something is permanently wrong. |
| 10 // |
| 11 // Said another way, transient errors appear to resolve themselves with nothing |
| 12 // other than the passage of time. |
| 13 package transient |
| 14 |
| 15 import ( |
| 16 "time" |
| 17 |
| 18 "github.com/luci/luci-go/common/errors" |
| 19 "github.com/luci/luci-go/common/retry" |
| 20 "golang.org/x/net/context" |
| 21 ) |
| 22 |
| 23 // transientOnlyIterator is an Iterator implementation that only retries errors |
| 24 // if they are tagged with `transient.Tag`. |
| 25 type transientOnlyIterator struct { |
| 26 retry.Iterator // The wrapped Iterator. |
| 27 } |
| 28 |
| 29 func (i *transientOnlyIterator) Next(ctx context.Context, err error) time.Durati
on { |
| 30 if !Tag.In(err) { |
| 31 return retry.Stop |
| 32 } |
| 33 return i.Iterator.Next(ctx, err) |
| 34 } |
| 35 |
| 36 // Only returns a retry.Iterator that wraps another retry.Iterator. It |
| 37 // will fall through to the wrapped Iterator ONLY if an error with the |
| 38 // transient.Tag is encountered; otherwise, it will not retry. |
| 39 // |
| 40 // Returns nil if f is nil. |
| 41 // |
| 42 // Example: |
| 43 // err := retry.Retry(c, transient.Only(retry.Default), func() error { |
| 44 // if condition == "red" { |
| 45 // // This error isn't transient, so it won't be retried. |
| 46 // return errors.New("fatal bad condition") |
| 47 // } elif condition == "green" { |
| 48 // // This isn't an error, so it won't be retried. |
| 49 // return nil |
| 50 // } |
| 51 // // This will get retried, because it's transient. |
| 52 // return errors.New("dunno what's wrong", transient.Tag) |
| 53 // }) |
| 54 func Only(next retry.Factory) retry.Factory { |
| 55 if next == nil { |
| 56 return nil |
| 57 } |
| 58 return func() retry.Iterator { |
| 59 if it := next(); it != nil { |
| 60 return &transientOnlyIterator{it} |
| 61 } |
| 62 return nil |
| 63 } |
| 64 } |
| 65 |
| 66 // Tag is used to indicate that an error is transient (i.e. something is |
| 67 // temporarially wrong). |
| 68 var Tag = errors.BoolTag{Key: errors.NewTagKey("this error is temporary")} |
OLD | NEW |