watch/view.go
func (v *View) fetch(doneCh, successCh chan<- struct{}, errCh chan<- error) {
	log.Printf("[TRACE] (view) %s starting fetch", v.dependency)

	var allowStale bool
	if v.maxStale != 0 {
		allowStale = true
	}

	for {
		// If the view was stopped, short-circuit this loop. This prevents a bug
		// where a view can get "lost" in the event Consul Template is reloaded.
		select {
		case <-v.stopCh:
			return
		default:
		}

		data, rm, err := v.dependency.Fetch(v.clients, &dep.QueryOptions{
			AllowStale: allowStale,
			WaitTime:   defaultWaitTime,
			WaitIndex:  v.lastIndex,
			VaultGrace: v.vaultGrace,
		})
		if err != nil {
			if err == dep.ErrStopped {
				log.Printf("[TRACE] (view) %s reported stop", v.dependency)
			} else {
				errCh <- err
			}
			return
		}

		if rm == nil {
			errCh <- fmt.Errorf("received nil response metadata - this is a bug " +
				"and should be reported")
			return
		}

		// If we got this far, we received data successfully. That data might not
		// trigger a data update (because we could continue below), but we need to
		// inform the poller to reset the retry count.
		log.Printf("[TRACE] (view) %s marking successful data response", v.dependency)
		select {
		case successCh <- struct{}{}:
		default:
		}

		if allowStale && rm.LastContact > v.maxStale {
			allowStale = false
			log.Printf("[TRACE] (view) %s stale data (last contact exceeded max_stale)", v.dependency)
			continue
		}

		if v.maxStale != 0 {
			allowStale = true
		}

		if rm.LastIndex == v.lastIndex {
			log.Printf("[TRACE] (view) %s no new data (index was the same)", v.dependency)
			continue
		}

		v.dataLock.Lock()
		if rm.LastIndex < v.lastIndex {
			log.Printf("[TRACE] (view) %s had a lower index, resetting", v.dependency)
			v.lastIndex = 0
			v.dataLock.Unlock()
			continue
		}
		v.lastIndex = rm.LastIndex

		if v.receivedData && reflect.DeepEqual(data, v.data) {
			log.Printf("[TRACE] (view) %s no new data (contents were the same)", v.dependency)
			v.dataLock.Unlock()
			continue
		}

		if data == nil && rm.Block {
			log.Printf("[TRACE] (view) %s asked for blocking query", v.dependency)
			v.dataLock.Unlock()
			continue
		}

		v.data = data
		v.receivedData = true
		v.dataLock.Unlock()

		close(doneCh)
		return
	}
}
func (v *View) fetch(doneCh, successCh chan<- struct{}, errCh chan<- error) {
	log.Printf("[TRACE] (view) %s starting fetch", v.dependency)

	var allowStale bool
	if v.maxStale != 0 {
		allowStale = true
	}

	for {
		// If the view was stopped, short-circuit this loop. This prevents a bug
		// where a view can get "lost" in the event Consul Template is reloaded.
		select {
		case <-v.stopCh:
			return
		default:
		}

		data, rm, err := v.dependency.Fetch(v.clients, &dep.QueryOptions{
			AllowStale: allowStale,
			WaitTime:   defaultWaitTime,
			WaitIndex:  v.lastIndex,
			VaultGrace: v.vaultGrace,
		})
		if err != nil {
			if err == dep.ErrStopped {
				log.Printf("[TRACE] (view) %s reported stop", v.dependency)
			} else {
				errCh <- err
			}
			return
		}

		if rm == nil {
			errCh <- fmt.Errorf("received nil response metadata - this is a bug " +
				"and should be reported")
			return
		}

		// If we got this far, we received data successfully. That data might not
		// trigger a data update (because we could continue below), but we need to
		// inform the poller to reset the retry count.
		log.Printf("[TRACE] (view) %s marking successful data response", v.dependency)
		select {
		case successCh <- struct{}{}:
		default:
		}

		if allowStale && rm.LastContact > v.maxStale {
			allowStale = false
			log.Printf("[TRACE] (view) %s stale data (last contact exceeded max_stale)", v.dependency)
			continue
		}

		if v.maxStale != 0 {
			allowStale = true
		}

		if rm.LastIndex == v.lastIndex {
			log.Printf("[TRACE] (view) %s no new data (index was the same)", v.dependency)
			continue
		}

		v.dataLock.Lock()
		if rm.LastIndex < v.lastIndex {
			log.Printf("[TRACE] (view) %s had a lower index, resetting", v.dependency)
			v.lastIndex = 0
			v.dataLock.Unlock()
			continue
		}
		v.lastIndex = rm.LastIndex

		if v.receivedData && reflect.DeepEqual(data, v.data) {
			log.Printf("[TRACE] (view) %s no new data (contents were the same)", v.dependency)
			v.dataLock.Unlock()
			continue
		}

		if data == nil && rm.Block {
			log.Printf("[TRACE] (view) %s asked for blocking query", v.dependency)
			v.dataLock.Unlock()
			continue
		}

		v.data = data
		v.receivedData = true
		v.dataLock.Unlock()

		close(doneCh)
		return
	}
}
func ( v * View ) fetch ( doneCh , successCh chan <- struct { } , errCh chan <- error ) { log . Printf ( " " , v . dependency ) var allowStale bool if v . maxStale != 0 { allowStale = true } for { // If the view was stopped, short-circuit this loop. This prevents a bug // where a view can get "lost" in the event Consul Template is reloaded. select { case <- v . stopCh : return default : } data , rm , err := v . dependency . Fetch ( v . clients , & dep . QueryOptions { AllowStale : allowStale , WaitTime : defaultWaitTime , WaitIndex : v . lastIndex , VaultGrace : v . vaultGrace , } ) if err != nil { if err == dep . ErrStopped { log . Printf ( " " , v . dependency ) } else { errCh <- err } return } if rm == nil { errCh <- fmt . Errorf ( " " + " " ) return } // If we got this far, we received data successfully. That data might not // trigger a data update (because we could continue below), but we need to // inform the poller to reset the retry count. log . Printf ( " " , v . dependency ) select { case successCh <- struct { } { } : default : } if allowStale && rm . LastContact > v . maxStale { allowStale = false log . Printf ( " " , v . dependency ) continue } if v . maxStale != 0 { allowStale = true } if rm . LastIndex == v . lastIndex { log . Printf ( " " , v . dependency ) continue } v . dataLock . Lock ( ) if rm . LastIndex < v . lastIndex { log . Printf ( " " , v . dependency ) v . lastIndex = 0 v . dataLock . Unlock ( ) continue } v . lastIndex = rm . LastIndex if v . receivedData && reflect . DeepEqual ( data , v . data ) { log . Printf ( " " , v . dependency ) v . dataLock . Unlock ( ) continue } if data == nil && rm . Block { log . Printf ( " " , v . dependency ) v . dataLock . Unlock ( ) continue } v . data = data v . receivedData = true v . dataLock . Unlock ( ) close ( doneCh ) return } }
// fetch queries the Consul instance for the attached dependency. This API
// promises that either data will be written to doneCh or an error will be
// written to errCh. It is designed to be run in a goroutine that selects the
// result of doneCh and errCh. It is assumed that only one instance of fetch
// is running per View and therefore no locking or mutexes are used.
fetch queries the Consul instance for the attached dependency . This API promises that either data will be written to doneCh or an error will be written to errCh . It is designed to be run in a goroutine that selects the result of doneCh and errCh . It is assumed that only one instance of fetch is running per View and therefore no locking or mutexes are used .