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 }