github.com/haraldrudell/parl@v0.4.176/ptime/on-ticker-thread.go (about) 1 /* 2 © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package ptime 7 8 import ( 9 "context" 10 "time" 11 12 "github.com/haraldrudell/parl/internal/cyclebreaker" 13 "github.com/haraldrudell/parl/perrors" 14 ) 15 16 type Go interface { 17 Done(err *error) 18 Context() (ctx context.Context) 19 } 20 21 // OnTickerThread is a goroutine that invokes a callback periodically 22 // - period must be greater than zero or panic 23 // - loc is optional time zone, default time.Local, other time zone is time.UTC 24 // - — time zone matters for periods longer than 1 hour or time-zone offiset minutes 25 // - g can be nil, in which panics are echoed to standard error. 26 // The thread is then not awaitable or cancelable 27 // - OnTickerThread is a time.Ticker using on-period multiples that invokes 28 // a callback periodically without further action 29 // - OnTickerThread eliminates channel receive actions at 30 // the cost of an additional OnTickerThread thread 31 // - a thread-less on-period ticker is OnTicker 32 func OnTickerThread(callback func(at time.Time), period time.Duration, loc *time.Location, g Go) { 33 var err error 34 if g != nil { 35 defer g.Done(&err) 36 defer cyclebreaker.Recover(func() cyclebreaker.DA { return cyclebreaker.A() }, &err, cyclebreaker.NoOnError) 37 } else { 38 defer cyclebreaker.Recover(func() cyclebreaker.DA { return cyclebreaker.A() }, &err, cyclebreaker.Infallible) 39 } 40 41 if callback == nil { 42 err = perrors.NewPF("callback cannot be nil") 43 return 44 } 45 46 var ticker = NewOnTicker(period, loc) 47 defer ticker.Stop() 48 49 C := ticker.C 50 var done <-chan struct{} 51 if g != nil { 52 done = g.Context().Done() 53 } 54 var t time.Time 55 for { 56 select { 57 case <-done: 58 return // context canceled return 59 case t = <-C: 60 } 61 62 callback(t) 63 } 64 }