timing.go (2072B)
1 package sched 2 3 import ( 4 "time" 5 ) 6 7 var ( 8 // zerotime is zero time.Time (unix epoch). 9 zerotime = time.Time{} 10 11 // emptytiming is a global timingempty to check against. 12 emptytiming = timingempty{} 13 ) 14 15 // Timing provides scheduling for a Job, determining the next time 16 // for given current time that execution is required. Please note that 17 // calls to .Next() may alter the results of the next call, and should 18 // only be called by the Scheduler. 19 type Timing interface { 20 Next(time.Time) time.Time 21 } 22 23 // timingempty is a 'zero' Timing implementation that always returns zero time. 24 type timingempty struct{} 25 26 func (timingempty) Next(time.Time) time.Time { 27 return zerotime 28 } 29 30 // Once implements Timing to provide a run-once Job execution. 31 type Once time.Time 32 33 func (o *Once) Next(time.Time) time.Time { 34 ret := *(*time.Time)(o) 35 *o = Once(zerotime) // reset 36 return ret 37 } 38 39 // Periodic implements Timing to provide a recurring Job execution. 40 type Periodic time.Duration 41 42 func (p Periodic) Next(now time.Time) time.Time { 43 return now.Add(time.Duration(p)) 44 } 45 46 // PeriodicAt implements Timing to provide a recurring Job execution starting at 'Once' time. 47 type PeriodicAt struct { 48 Once Once 49 Period Periodic 50 } 51 52 func (p *PeriodicAt) Next(now time.Time) time.Time { 53 if next := p.Once.Next(now); !next.IsZero() { 54 return next 55 } 56 return p.Period.Next(now) 57 } 58 59 // TimingWrap allows combining two different Timing implementations. 60 type TimingWrap struct { 61 Outer Timing 62 Inner Timing 63 64 // determined next times 65 outerNext time.Time 66 innerNext time.Time 67 } 68 69 func (t *TimingWrap) Next(now time.Time) time.Time { 70 if t.outerNext.IsZero() { 71 // Regenerate outermost next run time 72 t.outerNext = t.Outer.Next(now) 73 } 74 75 if t.innerNext.IsZero() { 76 // Regenerate innermost next run time 77 t.innerNext = t.Inner.Next(now) 78 } 79 80 // If outer comes before inner, return outer 81 if t.outerNext != zerotime && 82 t.outerNext.Before(t.innerNext) { 83 next := t.outerNext 84 t.outerNext = zerotime 85 return next 86 } 87 88 // Else, return inner 89 next := t.innerNext 90 t.innerNext = zerotime 91 return next 92 }