Example #1
0
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 (m *MockDetector) Detect(listener detector.MasterChanged) error {
	if listener != nil {
		if pid, err := upid.Parse("master(2)@" + m.address); err != nil {
			return err
		} else {
			go listener.OnMasterChanged(detector.CreateMasterInfo(pid))
		}
	}
	return nil
}
Example #3
0
func (md *MasterDetector) detect(f detector.MasterChanged) {

	minCyclePeriod := 1 * time.Second
detectLoop:
	for {
		started := time.Now()
		select {
		case <-md.Done():
			return
		case <-md.client.connections():
			// we let the golang runtime manage our listener list for us, in form of goroutines that
			// callback to the master change notification listen func's
			if watchEnded, err := md.client.watchChildren(currentPath, ChildWatcher(func(zkc *Client, path string) {
				md.childrenChanged(zkc, path, f)
			})); err == nil {
				log.V(2).Infoln("detector listener installed")
				select {
				case <-watchEnded:
					if md.leaderNode != "" {
						log.V(1).Infof("child watch ended, signaling master lost")
						md.leaderNode = ""
						f.OnMasterChanged(nil)
					}
				case <-md.client.stopped():
					return
				}
			} else {
				log.V(1).Infof("child watch ended with error: %v", err)
				continue detectLoop
			}
		}
		// 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(minCyclePeriod - elapsed): // noop
			}
		}
	}
}
Example #4
0
func (md *MasterDetector) notifyMasterChanged(path string, list []string, obs detector.MasterChanged) {
	topNode := 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 %s -> %s", md.leaderNode, topNode)
	md.leaderNode = topNode

	var masterInfo *mesos.MasterInfo
	if md.leaderNode != "" {
		var err error
		if masterInfo, err = md.pullMasterInfo(path, topNode); err != nil {
			log.Errorln(err.Error())
		}
	}
	log.V(2).Infof("detected master info: %+v", masterInfo)
	logPanic(func() { obs.OnMasterChanged(masterInfo) })
}
Example #5
0
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) })
}
Example #6
0
//TODO(jdef) execute async because we don't want to stall our client's event loop? if so
//then we also probably want serial event delivery (aka. delivery via a chan) but then we
//have to deal with chan buffer sizes .. ugh. This is probably the least painful for now.
func (md *MasterDetector) childrenChanged(zkc *Client, path string, obs detector.MasterChanged) {
	log.V(2).Infof("fetching children at path '%v'", path)
	list, err := zkc.list(path)
	if err != nil {
		log.Warning(err)
		return
	}

	topNode := 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 %s -> %s", md.leaderNode, topNode)
	md.leaderNode = topNode

	var masterInfo *mesos.MasterInfo
	if md.leaderNode != "" {
		data, err := zkc.data(fmt.Sprintf("%s/%s", path, topNode))
		if err != nil {
			log.Errorf("unable to retrieve leader data: %v", err.Error())
			return
		}

		masterInfo = new(mesos.MasterInfo)
		err = proto.Unmarshal(data, masterInfo)
		if err != nil {
			log.Errorf("unable to unmarshall MasterInfo data from zookeeper: %v", err)
			return
		}
	}
	log.V(2).Infof("detected master info: %+v", masterInfo)
	obs.OnMasterChanged(masterInfo)
}
Example #7
0
func (md FakeMasterDetector) Detect(cb detector.MasterChanged) error {
	md.callback = cb
	leadingMaster := mesosutil.NewMasterInfo(TEST_MASTER_ID, TEST_MASTER_IP, TEST_MASTER_PORT)
	cb.OnMasterChanged(leadingMaster)
	return nil
}