github.com/haraldrudell/parl@v0.4.176/periodically.go (about)

     1  /*
     2  © 2022–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
     3  ISC License
     4  */
     5  
     6  package parl
     7  
     8  import (
     9  	"context"
    10  	"sync"
    11  	"time"
    12  )
    13  
    14  const (
    15  	defaultPeriod = time.Second
    16  )
    17  
    18  type Periodically struct {
    19  	period time.Duration
    20  	fn     func(t time.Time)
    21  	wg     sync.WaitGroup
    22  	ctx    context.Context
    23  }
    24  
    25  func NewPeriodically(fn func(t time.Time), ctx context.Context, period ...time.Duration) (periodically *Periodically) {
    26  	p := Periodically{ctx: ctx, fn: fn}
    27  	if len(period) > 0 {
    28  		p.period = period[0]
    29  	}
    30  	if p.period < defaultPeriod {
    31  		p.period = defaultPeriod
    32  	}
    33  	p.wg.Add(1)
    34  	go p.doThread()
    35  	return &p
    36  }
    37  
    38  func (p *Periodically) Wait() {
    39  	p.wg.Wait()
    40  }
    41  
    42  func (p *Periodically) doThread() {
    43  	defer p.wg.Done()
    44  	defer Recover(func() DA { return A() }, nil, Infallible)
    45  
    46  	ticker := time.NewTicker(p.period)
    47  	defer ticker.Stop()
    48  
    49  	done := p.ctx.Done()
    50  	for {
    51  		select {
    52  		case <-done:
    53  			return // context cancel exit
    54  		case t := <-ticker.C:
    55  			go p.doFn(t)
    56  		}
    57  	}
    58  }
    59  
    60  func (p *Periodically) doFn(t time.Time) {
    61  	defer Recover(func() DA { return A() }, nil, Infallible)
    62  
    63  	p.fn(t)
    64  }