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 }