~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/utils/attempt.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2011, 2012, 2013 Canonical Ltd.
 
2
// Licensed under the LGPLv3, see LICENCE file for details.
 
3
 
 
4
package utils
 
5
 
 
6
import (
 
7
        "time"
 
8
)
 
9
 
 
10
// The Attempt and AttemptStrategy types are copied from those in launchpad.net/goamz/aws.
 
11
 
 
12
// AttemptStrategy represents a strategy for waiting for an action
 
13
// to complete successfully.
 
14
type AttemptStrategy struct {
 
15
        Total time.Duration // total duration of attempt.
 
16
        Delay time.Duration // interval between each try in the burst.
 
17
        Min   int           // minimum number of retries; overrides Total
 
18
}
 
19
 
 
20
type Attempt struct {
 
21
        strategy AttemptStrategy
 
22
        last     time.Time
 
23
        end      time.Time
 
24
        force    bool
 
25
        count    int
 
26
}
 
27
 
 
28
// Start begins a new sequence of attempts for the given strategy.
 
29
func (s AttemptStrategy) Start() *Attempt {
 
30
        now := time.Now()
 
31
        return &Attempt{
 
32
                strategy: s,
 
33
                last:     now,
 
34
                end:      now.Add(s.Total),
 
35
                force:    true,
 
36
        }
 
37
}
 
38
 
 
39
// Next waits until it is time to perform the next attempt or returns
 
40
// false if it is time to stop trying.
 
41
// It always returns true the first time it is called - we are guaranteed to
 
42
// make at least one attempt.
 
43
func (a *Attempt) Next() bool {
 
44
        now := time.Now()
 
45
        sleep := a.nextSleep(now)
 
46
        if !a.force && !now.Add(sleep).Before(a.end) && a.strategy.Min <= a.count {
 
47
                return false
 
48
        }
 
49
        a.force = false
 
50
        if sleep > 0 && a.count > 0 {
 
51
                time.Sleep(sleep)
 
52
                now = time.Now()
 
53
        }
 
54
        a.count++
 
55
        a.last = now
 
56
        return true
 
57
}
 
58
 
 
59
func (a *Attempt) nextSleep(now time.Time) time.Duration {
 
60
        sleep := a.strategy.Delay - now.Sub(a.last)
 
61
        if sleep < 0 {
 
62
                return 0
 
63
        }
 
64
        return sleep
 
65
}
 
66
 
 
67
// HasNext returns whether another attempt will be made if the current
 
68
// one fails. If it returns true, the following call to Next is
 
69
// guaranteed to return true.
 
70
func (a *Attempt) HasNext() bool {
 
71
        if a.force || a.strategy.Min > a.count {
 
72
                return true
 
73
        }
 
74
        now := time.Now()
 
75
        if now.Add(a.nextSleep(now)).Before(a.end) {
 
76
                a.force = true
 
77
                return true
 
78
        }
 
79
        return false
 
80
}