github.com/yandex/pandora@v0.5.32/core/schedule/do_at.go (about)

     1  package schedule
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/yandex/pandora/core"
     7  	"go.uber.org/atomic"
     8  )
     9  
    10  // DoAt returns when i'th operation should be performed, assuming that schedule
    11  // started at 0.
    12  type DoAt func(i int64) time.Duration
    13  
    14  func NewDoAtSchedule(duration time.Duration, n int64, doAt DoAt) core.Schedule {
    15  	return &doAtSchedule{
    16  		duration: duration,
    17  		n:        n,
    18  		doAt:     doAt,
    19  	}
    20  }
    21  
    22  type doAtSchedule struct {
    23  	duration time.Duration
    24  	n        int64
    25  	i        atomic.Int64
    26  	doAt     func(i int64) time.Duration
    27  
    28  	StartSync
    29  	start time.Time
    30  }
    31  
    32  func (s *doAtSchedule) Start(startAt time.Time) {
    33  	s.MarkStarted()
    34  	s.startOnce.Do(func() {
    35  		s.start = startAt
    36  	})
    37  }
    38  
    39  func (s *doAtSchedule) Next() (tx time.Time, ok bool) {
    40  	s.startOnce.Do(func() {
    41  		// No allocations here due to benchmark.
    42  		s.MarkStarted()
    43  		s.start = time.Now()
    44  	})
    45  	i := s.i.Inc() - 1
    46  	if i >= s.n {
    47  		return s.start.Add(s.duration), false
    48  	}
    49  	return s.start.Add(s.doAt(i)), true
    50  }
    51  
    52  func (s *doAtSchedule) Left() int {
    53  	left := int(s.n - s.i.Load())
    54  	if left < 0 {
    55  		return 0
    56  	}
    57  	return left
    58  }