package memberlist import ( "sync" "time" "github.com/armon/go-metrics" ) // awareness manages a simple metric for tracking the estimated health of the // local node. Health is primary the node's ability to respond in the soft // real-time manner required for correct health checking of other nodes in the // cluster. type awareness struct { sync.RWMutex // max is the upper threshold for the timeout scale (the score will be // constrained to be from 0 <= score < max). max int // score is the current awareness score. Lower values are healthier and // zero is the minimum value. score int } // newAwareness returns a new awareness object. func newAwareness(max int) *awareness { return &awareness{ max: max, score: 0, } } // ApplyDelta takes the given delta and applies it to the score in a thread-safe // manner. It also enforces a floor of zero and a max of max, so deltas may not // change the overall score if it's railed at one of the extremes. func (a *awareness) ApplyDelta(delta int) { a.Lock() initial := a.score a.score += delta if a.score < 0 { a.score = 0 } else if a.score > (a.max - 1) { a.score = (a.max - 1) } final := a.score a.Unlock() if initial != final { metrics.SetGauge([]string{"memberlist", "health", "score"}, float32(final)) } } // GetHealthScore returns the raw health score. func (a *awareness) GetHealthScore() int { a.RLock() score := a.score a.RUnlock() return score } // ScaleTimeout takes the given duration and scales it based on the current // score. Less healthyness will lead to longer timeouts. func (a *awareness) ScaleTimeout(timeout time.Duration) time.Duration { a.RLock() score := a.score a.RUnlock() return timeout * (time.Duration(score) + 1) }