github.com/git-amp/amp-sdk-go@v0.7.5/stdlib/utils/time.go (about)

     1  package utils
     2  
     3  import (
     4  	"time"
     5  )
     6  
     7  type ExponentialBackoff struct {
     8  	Min          time.Duration
     9  	Max          time.Duration
    10  	current      time.Duration
    11  	previousIncr time.Time
    12  }
    13  
    14  func (eb *ExponentialBackoff) Ready() (ready bool, until time.Duration) {
    15  	if eb.previousIncr.IsZero() {
    16  		return true, 0
    17  	}
    18  	whenReady := eb.previousIncr.Add(eb.current)
    19  	ready = time.Now().After(whenReady)
    20  	if !ready {
    21  		until = whenReady.Sub(time.Now())
    22  	}
    23  	return
    24  }
    25  
    26  func (eb *ExponentialBackoff) Next() time.Duration {
    27  	if eb.current == 0 {
    28  		eb.current = eb.Min
    29  	}
    30  	current := eb.current
    31  	eb.current *= 2
    32  	if eb.current > eb.Max {
    33  		eb.current = eb.Max
    34  	}
    35  	eb.previousIncr = time.Now()
    36  	return current
    37  }
    38  
    39  func (eb *ExponentialBackoff) Wait() {
    40  	time.Sleep(eb.Next())
    41  }
    42  
    43  func (eb *ExponentialBackoff) Reset() {
    44  	eb.current = eb.Min
    45  }
    46  
    47  type Ticker interface {
    48  	Start()
    49  	Close()
    50  	Notify() <-chan time.Time
    51  }
    52  
    53  type StaticTicker struct {
    54  	t        *time.Ticker
    55  	interval time.Duration
    56  }
    57  
    58  func NewStaticTicker(interval time.Duration) StaticTicker {
    59  	return StaticTicker{
    60  		t:        time.NewTicker(interval),
    61  		interval: interval,
    62  	}
    63  }
    64  
    65  func (t StaticTicker) Start() {
    66  	t.t.Reset(t.interval)
    67  }
    68  
    69  func (t StaticTicker) Close() {
    70  	t.t.Stop()
    71  }
    72  
    73  func (t StaticTicker) Notify() <-chan time.Time {
    74  	return t.t.C
    75  }
    76  
    77  type ExponentialBackoffTicker struct {
    78  	backoff ExponentialBackoff
    79  	chTick  chan time.Time
    80  	chReset chan struct{}
    81  	chStop  chan struct{}
    82  	chDone  chan struct{}
    83  }
    84  
    85  func NewExponentialBackoffTicker(min, max time.Duration) *ExponentialBackoffTicker {
    86  	return &ExponentialBackoffTicker{
    87  		backoff: ExponentialBackoff{Min: min, Max: max},
    88  		chTick:  make(chan time.Time),
    89  		chReset: make(chan struct{}),
    90  		chStop:  make(chan struct{}),
    91  		chDone:  make(chan struct{}),
    92  	}
    93  }
    94  
    95  func (t *ExponentialBackoffTicker) Start() {
    96  	go func() {
    97  		defer close(t.chDone)
    98  		for {
    99  			func() {
   100  				duration := t.backoff.Next()
   101  				timer := time.NewTimer(duration)
   102  				defer timer.Stop()
   103  
   104  				select {
   105  				case <-t.chStop:
   106  					return
   107  
   108  				case <-t.chReset:
   109  					t.backoff.Reset()
   110  
   111  				case now := <-timer.C:
   112  					select {
   113  					case <-t.chStop:
   114  						return
   115  					case t.chTick <- now:
   116  					}
   117  				}
   118  			}()
   119  		}
   120  	}()
   121  }
   122  
   123  func (t *ExponentialBackoffTicker) Reset() {
   124  	select {
   125  	case <-t.chStop:
   126  	case t.chReset <- struct{}{}:
   127  	}
   128  }
   129  
   130  func (t *ExponentialBackoffTicker) Close() {
   131  	close(t.chStop)
   132  	<-t.chDone
   133  }
   134  
   135  func (t *ExponentialBackoffTicker) Notify() <-chan time.Time {
   136  	return t.chTick
   137  }