Replace the exported OnIntervalRoutine struct (Start/Stop/UpdateInterval) with a single function that auto-starts the goroutine and returns an idempotent stop closure. Uses close(channel) instead of send-on-channel, fixing a potential deadlock when the goroutine exits via context disposal. Closes #5 item 4.
33 lines
513 B
Go
33 lines
513 B
Go
package via
|
|
|
|
import (
|
|
"sync/atomic"
|
|
"time"
|
|
)
|
|
|
|
func newOnInterval(ctxDisposedChan chan struct{}, duration time.Duration, handler func()) func() {
|
|
localInterrupt := make(chan struct{})
|
|
var stopped atomic.Bool
|
|
|
|
go func() {
|
|
tkr := time.NewTicker(duration)
|
|
defer tkr.Stop()
|
|
for {
|
|
select {
|
|
case <-ctxDisposedChan:
|
|
return
|
|
case <-localInterrupt:
|
|
return
|
|
case <-tkr.C:
|
|
handler()
|
|
}
|
|
}
|
|
}()
|
|
|
|
return func() {
|
|
if stopped.CompareAndSwap(false, true) {
|
|
close(localInterrupt)
|
|
}
|
|
}
|
|
}
|