77 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Go
		
	
	
			
		
		
	
	
			77 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Go
		
	
	
package util
 | 
						|
 | 
						|
import (
 | 
						|
	"time"
 | 
						|
)
 | 
						|
 | 
						|
// AttemptStrategy is reused from the goamz package
 | 
						|
 | 
						|
// AttemptStrategy represents a strategy for waiting for an action
 | 
						|
// to complete successfully. This is an internal type used by the
 | 
						|
// implementation of other packages.
 | 
						|
type AttemptStrategy struct {
 | 
						|
	Total time.Duration // total duration of attempt.
 | 
						|
	Delay time.Duration // interval between each try in the burst.
 | 
						|
	Min   int           // minimum number of retries; overrides Total
 | 
						|
}
 | 
						|
 | 
						|
type Attempt struct {
 | 
						|
	strategy AttemptStrategy
 | 
						|
	last     time.Time
 | 
						|
	end      time.Time
 | 
						|
	force    bool
 | 
						|
	count    int
 | 
						|
}
 | 
						|
 | 
						|
// Start begins a new sequence of attempts for the given strategy.
 | 
						|
func (s AttemptStrategy) Start() *Attempt {
 | 
						|
	now := time.Now()
 | 
						|
	return &Attempt{
 | 
						|
		strategy: s,
 | 
						|
		last:     now,
 | 
						|
		end:      now.Add(s.Total),
 | 
						|
		force:    true,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Next waits until it is time to perform the next attempt or returns
 | 
						|
// false if it is time to stop trying.
 | 
						|
func (a *Attempt) Next() bool {
 | 
						|
	now := time.Now()
 | 
						|
	sleep := a.nextSleep(now)
 | 
						|
	if !a.force && !now.Add(sleep).Before(a.end) && a.strategy.Min <= a.count {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
	a.force = false
 | 
						|
	if sleep > 0 && a.count > 0 {
 | 
						|
		time.Sleep(sleep)
 | 
						|
		now = time.Now()
 | 
						|
	}
 | 
						|
	a.count++
 | 
						|
	a.last = now
 | 
						|
	return true
 | 
						|
}
 | 
						|
 | 
						|
func (a *Attempt) nextSleep(now time.Time) time.Duration {
 | 
						|
	sleep := a.strategy.Delay - now.Sub(a.last)
 | 
						|
	if sleep < 0 {
 | 
						|
		return 0
 | 
						|
	}
 | 
						|
	return sleep
 | 
						|
}
 | 
						|
 | 
						|
// HasNext returns whether another attempt will be made if the current
 | 
						|
// one fails. If it returns true, the following call to Next is
 | 
						|
// guaranteed to return true.
 | 
						|
func (a *Attempt) HasNext() bool {
 | 
						|
	if a.force || a.strategy.Min > a.count {
 | 
						|
		return true
 | 
						|
	}
 | 
						|
	now := time.Now()
 | 
						|
	if now.Add(a.nextSleep(now)).Before(a.end) {
 | 
						|
		a.force = true
 | 
						|
		return true
 | 
						|
	}
 | 
						|
	return false
 | 
						|
}
 |