github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/api/monitor.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package api
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/utils/clock"
    10  )
    11  
    12  // monitor performs regular pings of an API connection as well as
    13  // monitoring the connection closed channel and the underlying
    14  // rpc.Conn's dead channel. It will close `broken` if pings fail, or
    15  // if `closed` or `dead` are closed.
    16  type monitor struct {
    17  	clock clock.Clock
    18  
    19  	ping        func() error
    20  	pingPeriod  time.Duration
    21  	pingTimeout time.Duration
    22  
    23  	closed <-chan struct{}
    24  	dead   <-chan struct{}
    25  	broken chan<- struct{}
    26  }
    27  
    28  func (m *monitor) run() {
    29  	defer close(m.broken)
    30  	for {
    31  		select {
    32  		case <-m.closed:
    33  			return
    34  		case <-m.dead:
    35  			logger.Debugf("RPC connection died")
    36  			return
    37  		case <-m.clock.After(m.pingPeriod):
    38  			if !m.pingWithTimeout() {
    39  				return
    40  			}
    41  		}
    42  	}
    43  }
    44  
    45  func (m *monitor) pingWithTimeout() bool {
    46  	result := make(chan error, 1)
    47  	go func() {
    48  		// Note that result is buffered so that we don't leak this
    49  		// goroutine when a timeout happens.
    50  		result <- m.ping()
    51  	}()
    52  	select {
    53  	case err := <-result:
    54  		if err != nil {
    55  			logger.Debugf("health ping failed: %v", err)
    56  		}
    57  		return err == nil
    58  	case <-m.clock.After(m.pingTimeout):
    59  		logger.Errorf("health ping timed out after %s", m.pingTimeout)
    60  		return false
    61  	}
    62  }