func (self *NsqLookupdEtcdMgr) WatchNsqdNodes(nsqds chan []NsqdNodeInfo, stop chan struct{}) { nsqdNodes, err := self.getNsqdNodes() if err == nil { select { case nsqds <- nsqdNodes: case <-stop: close(nsqds) return } } key := self.createNsqdRootPath() watcher := self.client.Watch(key, 0, true) ctx, cancel := context.WithCancel(context.Background()) go func() { select { case <-stop: cancel() case <-self.watchNsqdNodesStopCh: cancel() } }() for { rsp, err := watcher.Next(ctx) if err != nil { if err == context.Canceled { coordLog.Infof("watch key[%s] canceled.", key) close(nsqds) return } else { coordLog.Errorf("watcher key[%s] error: %s", key, err.Error()) //rewatch if etcdlock.IsEtcdWatchExpired(err) { rsp, err = self.client.Get(key, false, true) if err != nil { coordLog.Errorf("rewatch and get key[%s] error: %s", key, err.Error()) continue } watcher = self.client.Watch(key, rsp.Index+1, true) // should get the nodes to notify watcher since last watch is expired } else { time.Sleep(5 * time.Second) continue } } } nsqdNodes, err := self.getNsqdNodes() if err != nil { coordLog.Errorf("key[%s] getNsqdNodes error: %s", key, err.Error()) continue } select { case nsqds <- nsqdNodes: case <-stop: close(nsqds) return } } }
// watch topics if changed func (self *NsqLookupdEtcdMgr) watchTopics() { watcher := self.client.Watch(self.topicRoot, 0, true) ctx, cancel := context.WithCancel(context.Background()) go func() { select { case <-self.watchTopicsStopCh: cancel() } }() for { _, err := watcher.Next(ctx) if err != nil { if err == context.Canceled { coordLog.Infof("watch key[%s] canceled.", self.topicRoot) return } else { coordLog.Errorf("watcher key[%s] error: %s", self.topicRoot, err.Error()) //rewatch if etcdlock.IsEtcdWatchExpired(err) { rsp, err := self.client.Get(self.topicRoot, false, true) if err != nil { coordLog.Errorf("rewatch and get key[%s] error: %s", self.topicRoot, err.Error()) continue } watcher = self.client.Watch(self.topicRoot, rsp.Index+1, true) // watch expired should be treated as changed of node } else { time.Sleep(5 * time.Second) continue } } } coordLog.Debugf("topic changed.") atomic.StoreInt32(&self.ifTopicChanged, 1) } }
func (self *NsqLookupdEtcdMgr) watchTopicLeaderSession(watchTopicLeaderInfo *WatchTopicLeaderInfo, leader chan *TopicLeaderSession) { topicLeaderSessionPath := self.createTopicLeaderSessionPath(watchTopicLeaderInfo.topic, watchTopicLeaderInfo.partition) watcher := self.client.Watch(topicLeaderSessionPath, 0, true) ctx, cancel := context.WithCancel(context.Background()) go func() { select { case <-watchTopicLeaderInfo.watchStopCh: cancel() } }() for { rsp, err := watcher.Next(ctx) if err != nil { if err == context.Canceled { coordLog.Infof("watch key[%s] canceled.", topicLeaderSessionPath) watchTopicLeaderInfo.stoppedCh <- true return } else { coordLog.Errorf("watcher key[%s] error: %s", topicLeaderSessionPath, err.Error()) //rewatch if etcdlock.IsEtcdWatchExpired(err) { rsp, err = self.client.Get(topicLeaderSessionPath, false, true) if err != nil { coordLog.Errorf("rewatch and get key[%s] error: %s", topicLeaderSessionPath, err.Error()) continue } watcher = self.client.Watch(topicLeaderSessionPath, rsp.Index+1, true) // watch changed since the expired event happened } else { time.Sleep(5 * time.Second) continue } } } if rsp == nil || rsp.Node == nil { continue } if rsp.PrevNode == nil { coordLog.Infof("watch key[%s] action[%s] value[%s] modified[%d]", rsp.Node.Key, rsp.Action, rsp.Node.Value, rsp.Node.ModifiedIndex) } else { coordLog.Debugf("watch key[%s] action[%s] value[%s] pre_modified[%d] modified[%d]", rsp.Node.Key, rsp.Action, rsp.Node.Value, rsp.PrevNode.ModifiedIndex, rsp.Node.ModifiedIndex) } if rsp.Action == "compareAndDelete" || rsp.Action == "delete" || rsp.Action == "expire" { keys := strings.Split(rsp.Node.Key, "/") keyLen := len(keys) if keyLen < 3 { continue } partition, err := strconv.Atoi(keys[keyLen-2]) if err != nil { continue } coordLog.Infof("topic[%s] partition[%d] action[%s] leader deleted.", keys[keyLen-3], partition, rsp.Action) topicLeaderSession := &TopicLeaderSession{ Topic: keys[keyLen-3], Partition: partition, } leader <- topicLeaderSession } else if rsp.Action == "create" { var topicLeaderSession TopicLeaderSession if err := json.Unmarshal([]byte(rsp.Node.Value), &topicLeaderSession); err != nil { continue } coordLog.Infof("topicLeaderSession[%v] create.", topicLeaderSession) leader <- &topicLeaderSession } } }
func (self *NsqdEtcdMgr) WatchLookupdLeader(leader chan *NsqLookupdNodeInfo, stop chan struct{}) error { key := self.createLookupdLeaderPath() rsp, err := self.client.Get(key, false, false) if err == nil { coordLog.Infof("key: %s value: %s", rsp.Node.Key, rsp.Node.Value) var lookupdInfo NsqLookupdNodeInfo err = json.Unmarshal([]byte(rsp.Node.Value), &lookupdInfo) if err == nil { select { case leader <- &lookupdInfo: case <-stop: close(leader) return nil } } } else { coordLog.Errorf("get error: %s", err.Error()) } watcher := self.client.Watch(key, 0, true) ctx, cancel := context.WithCancel(context.Background()) go func() { select { case <-stop: cancel() } }() for { rsp, err = watcher.Next(ctx) if err != nil { if err == context.Canceled { coordLog.Infof("watch key[%s] canceled.", key) close(leader) return nil } else { coordLog.Errorf("watcher key[%s] error: %s", key, err.Error()) //rewatch if etcdlock.IsEtcdWatchExpired(err) { rsp, err = self.client.Get(key, false, true) if err != nil { coordLog.Errorf("rewatch and get key[%s] error: %s", key, err.Error()) continue } watcher = self.client.Watch(key, rsp.Index+1, true) } else { time.Sleep(5 * time.Second) continue } } } if rsp == nil { continue } var lookupdInfo NsqLookupdNodeInfo if rsp.Action == "expire" || rsp.Action == "delete" { coordLog.Infof("key[%s] action[%s]", key, rsp.Action) } else if rsp.Action == "create" || rsp.Action == "update" || rsp.Action == "set" { err := json.Unmarshal([]byte(rsp.Node.Value), &lookupdInfo) if err != nil { continue } } else { continue } select { case leader <- &lookupdInfo: case <-stop: close(leader) return nil } } return nil }