func (md *MasterDetector) detect(f detector.MasterChanged) { log.V(3).Infoln("detecting children at", currentPath) detectLoop: for { select { case <-md.Done(): return default: } log.V(3).Infoln("watching children at", currentPath) path, childrenCh, errCh := md.client.watchChildren(currentPath) rewatch := false for { started := time.Now() select { case children := <-childrenCh: md.childrenChanged(path, children, f) case err, ok := <-errCh: // check for a tie first (required for predictability (tests)); the downside of // doing this is that a listener might get two callbacks back-to-back ("new leader", // followed by "no leader"). select { case children := <-childrenCh: md.childrenChanged(path, children, f) default: } if ok { log.V(1).Infoln("child watch ended with error, master lost; error was:", err.Error()) } else { // detector shutdown likely... log.V(1).Infoln("child watch ended, master lost") } select { case <-md.Done(): return default: if md.leaderNode != "" { log.V(2).Infof("changing leader node from %q -> \"\"", md.leaderNode) md.leaderNode = "" f.OnMasterChanged(nil) } } rewatch = true } // rate-limit master changes if elapsed := time.Now().Sub(started); elapsed > 0 { log.V(2).Infoln("resting before next detection cycle") select { case <-md.Done(): return case <-time.After(md.minDetectorCyclePeriod - elapsed): // noop } } if rewatch { continue detectLoop } } } }
func (md *MasterDetector) notifyMasterChanged(path string, list []string, obs detector.MasterChanged) { // mesos v0.24 writes JSON only, v0.23 writes json and protobuf, v0.22 and prior only write protobuf topNode, codec := md.selectTopNode(list) if md.leaderNode == topNode { log.V(2).Infof("ignoring children-changed event, leader has not changed: %v", path) return } log.V(2).Infof("changing leader node from %q -> %q", md.leaderNode, topNode) md.leaderNode = topNode var masterInfo *mesos.MasterInfo if md.leaderNode != "" { var err error if masterInfo, err = codec(path, topNode); err != nil { log.Errorln(err.Error()) } } log.V(2).Infof("detected master info: %+v", masterInfo) logPanic(func() { obs.OnMasterChanged(masterInfo) }) }