mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 01:53:42 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			98 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			98 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package backoff
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"sync"
 | 
						|
	"time"
 | 
						|
)
 | 
						|
 | 
						|
// Ticker holds a channel that delivers `ticks' of a clock at times reported by a BackOff.
 | 
						|
//
 | 
						|
// Ticks will continue to arrive when the previous operation is still running,
 | 
						|
// so operations that take a while to fail could run in quick succession.
 | 
						|
type Ticker struct {
 | 
						|
	C        <-chan time.Time
 | 
						|
	c        chan time.Time
 | 
						|
	b        BackOff
 | 
						|
	ctx      context.Context
 | 
						|
	timer    Timer
 | 
						|
	stop     chan struct{}
 | 
						|
	stopOnce sync.Once
 | 
						|
}
 | 
						|
 | 
						|
// NewTicker returns a new Ticker containing a channel that will send
 | 
						|
// the time at times specified by the BackOff argument. Ticker is
 | 
						|
// guaranteed to tick at least once.  The channel is closed when Stop
 | 
						|
// method is called or BackOff stops. It is not safe to manipulate the
 | 
						|
// provided backoff policy (notably calling NextBackOff or Reset)
 | 
						|
// while the ticker is running.
 | 
						|
func NewTicker(b BackOff) *Ticker {
 | 
						|
	return NewTickerWithTimer(b, &defaultTimer{})
 | 
						|
}
 | 
						|
 | 
						|
// NewTickerWithTimer returns a new Ticker with a custom timer.
 | 
						|
// A default timer that uses system timer is used when nil is passed.
 | 
						|
func NewTickerWithTimer(b BackOff, timer Timer) *Ticker {
 | 
						|
	if timer == nil {
 | 
						|
		timer = &defaultTimer{}
 | 
						|
	}
 | 
						|
	c := make(chan time.Time)
 | 
						|
	t := &Ticker{
 | 
						|
		C:     c,
 | 
						|
		c:     c,
 | 
						|
		b:     b,
 | 
						|
		ctx:   getContext(b),
 | 
						|
		timer: timer,
 | 
						|
		stop:  make(chan struct{}),
 | 
						|
	}
 | 
						|
	t.b.Reset()
 | 
						|
	go t.run()
 | 
						|
	return t
 | 
						|
}
 | 
						|
 | 
						|
// Stop turns off a ticker. After Stop, no more ticks will be sent.
 | 
						|
func (t *Ticker) Stop() {
 | 
						|
	t.stopOnce.Do(func() { close(t.stop) })
 | 
						|
}
 | 
						|
 | 
						|
func (t *Ticker) run() {
 | 
						|
	c := t.c
 | 
						|
	defer close(c)
 | 
						|
 | 
						|
	// Ticker is guaranteed to tick at least once.
 | 
						|
	afterC := t.send(time.Now())
 | 
						|
 | 
						|
	for {
 | 
						|
		if afterC == nil {
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		select {
 | 
						|
		case tick := <-afterC:
 | 
						|
			afterC = t.send(tick)
 | 
						|
		case <-t.stop:
 | 
						|
			t.c = nil // Prevent future ticks from being sent to the channel.
 | 
						|
			return
 | 
						|
		case <-t.ctx.Done():
 | 
						|
			return
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (t *Ticker) send(tick time.Time) <-chan time.Time {
 | 
						|
	select {
 | 
						|
	case t.c <- tick:
 | 
						|
	case <-t.stop:
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	next := t.b.NextBackOff()
 | 
						|
	if next == Stop {
 | 
						|
		t.Stop()
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	t.timer.Start(next)
 | 
						|
	return t.timer.C()
 | 
						|
}
 |