code: func (c *Cache) runExpiryLoop() {
  	var expiryTimer *time.Timer
  	for {
  		// If we have a previous timer, stop it.
  		if expiryTimer != nil {
  			expiryTimer.Stop()
  		}
  
  		// Get the entry expiring soonest
  		var entry *cacheEntryExpiry
  		var expiryCh <-chan time.Time
  		c.entriesLock.RLock()
  		if len(c.entriesExpiryHeap.Entries) > 0 {
  			entry = c.entriesExpiryHeap.Entries[0]
  			expiryTimer = time.NewTimer(entry.Expires.Sub(time.Now()))
  			expiryCh = expiryTimer.C
  		}
  		c.entriesLock.RUnlock()
  
  		select {
  		case <-c.stopCh:
  			return
  		case <-c.entriesExpiryHeap.NotifyCh:
  			// Entries changed, so the heap may have changed. Restart loop.
  
  		case <-expiryCh:
  			c.entriesLock.Lock()
  
  			// Entry expired! Remove it.
  			delete(c.entries, entry.Key)
  			heap.Remove(c.entriesExpiryHeap, entry.HeapIndex)
  
  			// This is subtle but important: if we race and simultaneously
  			// evict and fetch a new value, then we set this to -1 to
  			// have it treated as a new value so that the TTL is extended.
  			entry.HeapIndex = -1
  
  			// Set some metrics
  			metrics.IncrCounter([]string{"consul", "cache", "evict_expired"}, 1)
  			metrics.SetGauge([]string{"consul", "cache", "entries_count"}, float32(len(c.entries)))
  
  			c.entriesLock.Unlock()
  		}
  	}
  }
docs: // runExpiryLoop is a blocking function that watches the expiration
  // heap and invalidates entries that have expired.