github.com/decred/dcrlnd@v0.7.6/ticker/ticker.go (about)

     1  package ticker
     2  
     3  import "time"
     4  
     5  // Ticker defines a resumable ticker interface, whose activity can be toggled to
     6  // free up resources during periods of inactivity.
     7  //
     8  // Example of resuming ticker:
     9  //
    10  //	ticker.Resume() // can remove to keep inactive at first
    11  //	defer ticker.Stop()
    12  //	for {
    13  //	  select {
    14  //	    case <-ticker.Tick():
    15  //	      if shouldGoInactive {
    16  //	        ticker.Pause()
    17  //	        continue
    18  //	      }
    19  //	      ...
    20  //
    21  //	    case <-otherEvent:
    22  //	      ...
    23  //	      if shouldGoActive {
    24  //	        ticker.Resume()
    25  //	      }
    26  //	  }
    27  //
    28  // NOTE: ONE DOES NOT SIMPLY assume that Tickers are safe for concurrent access.
    29  type Ticker interface {
    30  	// Ticks returns a read-only channel delivering ticks according to a
    31  	// prescribed interval. The value returned does not need to be the same
    32  	// channel, and may be nil.
    33  	//
    34  	// NOTE: Callers should assume that reads from Ticks() are stale after
    35  	// any invocations of Resume, Pause, or Stop.
    36  	Ticks() <-chan time.Time
    37  
    38  	// Resume starts or resumes the underlying ticker, such that Ticks()
    39  	// will fire at regular intervals. After calling Resume, Ticks() should
    40  	// minimally send ticks at the prescribed interval.
    41  	//
    42  	// NOTE: It MUST be safe to call Resume at any time, and more than once
    43  	// successively.
    44  	Resume()
    45  
    46  	// Pause suspends the underlying ticker, such that Ticks() stops
    47  	// signaling at regular intervals. After calling Pause, the ticker
    48  	// should not send any ticks scheduled with the chosen interval. Forced
    49  	// ticks are still permissible, as in the case of the Force Ticker.
    50  	//
    51  	// NOTE: It MUST be safe to call Pause at any time, and more than once
    52  	// successively.
    53  	Pause()
    54  
    55  	// Stop suspends the underlying ticker, such that Ticks() stops
    56  	// signaling at regular intervals, and permanently frees up any
    57  	// remaining resources.
    58  	//
    59  	// NOTE: The behavior of a Ticker is undefined after calling Stop.
    60  	Stop()
    61  }
    62  
    63  // T is the production implementation of the resumable Ticker interface. This
    64  // allows various components to toggle their need for tick events, which may
    65  // vary depending on system load.
    66  type T struct {
    67  	// interval is the desired duration between ticks when active.
    68  	interval time.Duration
    69  
    70  	// ticker is the ephemeral, underlying time.Ticker. We keep a reference
    71  	// to this ticker so that it can be stopped and cleaned up on Pause or
    72  	// Stop.
    73  	ticker *time.Ticker
    74  }
    75  
    76  // A compile-time constraint to ensure T satisfies the Ticker interface.
    77  var _ Ticker = (*T)(nil)
    78  
    79  // New returns a new ticker that signals with the given interval when not
    80  // paused. The ticker starts off inactive.
    81  func New(interval time.Duration) *T {
    82  	return &T{
    83  		interval: interval,
    84  	}
    85  }
    86  
    87  // Ticks returns a receive-only channel that delivers times at the ticker's
    88  // prescribed interval. This method returns nil when the ticker is paused.
    89  //
    90  // NOTE: Part of the Ticker interface.
    91  func (t *T) Ticks() <-chan time.Time {
    92  	if t.ticker == nil {
    93  		return nil
    94  	}
    95  	return t.ticker.C
    96  }
    97  
    98  // Resume starts underlying time.Ticker and causes the ticker to begin
    99  // delivering scheduled events.
   100  //
   101  // NOTE: Part of the Ticker interface.
   102  func (t *T) Resume() {
   103  	if t.ticker == nil {
   104  		t.ticker = time.NewTicker(t.interval)
   105  	}
   106  }
   107  
   108  // Pause suspends the underlying ticker, such that Ticks() stops signaling at
   109  // regular intervals.
   110  //
   111  // NOTE: Part of the Ticker interface.
   112  func (t *T) Pause() {
   113  	if t.ticker != nil {
   114  		t.ticker.Stop()
   115  		t.ticker = nil
   116  	}
   117  }
   118  
   119  // Stop suspends the underlying ticker, such that Ticks() stops signaling at
   120  // regular intervals, and permanently frees up any resources. For this
   121  // implementation, this is equivalent to Pause.
   122  //
   123  // NOTE: Part of the Ticker interface.
   124  func (t *T) Stop() {
   125  	t.Pause()
   126  }