github.com/iotexproject/iotex-core@v1.14.1-rc1/pkg/routine/recurringtask.go (about)

     1  // Copyright (c) 2018 IoTeX
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package routine
     7  
     8  import (
     9  	"context"
    10  	"time"
    11  
    12  	"github.com/facebookgo/clock"
    13  
    14  	"github.com/iotexproject/iotex-core/pkg/lifecycle"
    15  )
    16  
    17  var _ lifecycle.StartStopper = (*RecurringTask)(nil)
    18  
    19  // RecurringTaskOption is option to RecurringTask.
    20  type RecurringTaskOption interface {
    21  	SetRecurringTaskOption(*RecurringTask)
    22  }
    23  
    24  // RecurringTask represents a recurring task
    25  type RecurringTask struct {
    26  	lifecycle.Readiness
    27  	t        Task
    28  	interval time.Duration
    29  	ticker   *clock.Ticker
    30  	done     chan struct{}
    31  	clock    clock.Clock
    32  }
    33  
    34  // NewRecurringTask creates an instance of RecurringTask
    35  func NewRecurringTask(t Task, i time.Duration, ops ...RecurringTaskOption) *RecurringTask {
    36  	rt := &RecurringTask{
    37  		t:        t,
    38  		interval: i,
    39  		done:     make(chan struct{}),
    40  		clock:    clock.New(),
    41  	}
    42  	for _, opt := range ops {
    43  		opt.SetRecurringTaskOption(rt)
    44  	}
    45  	return rt
    46  }
    47  
    48  // Start starts the timer
    49  func (t *RecurringTask) Start(_ context.Context) error {
    50  	t.ticker = t.clock.Ticker(t.interval)
    51  	ready := make(chan struct{})
    52  	go func() {
    53  		close(ready)
    54  		for {
    55  			select {
    56  			case <-t.done:
    57  				return
    58  			case <-t.ticker.C:
    59  				t.t()
    60  			}
    61  		}
    62  	}()
    63  	// ensure the goroutine has been running
    64  	<-ready
    65  	return t.TurnOn()
    66  }
    67  
    68  // Stop stops the timer
    69  func (t *RecurringTask) Stop(_ context.Context) error {
    70  	// prevent stop is called before start.
    71  	if err := t.TurnOff(); err != nil {
    72  		return err
    73  	}
    74  	if t.ticker != nil {
    75  		t.ticker.Stop()
    76  	}
    77  	close(t.done)
    78  	return nil
    79  }