func (back *zkConfig) reregisterWatch(path string, logger log.Logger) error { logger = log.NewContext(logger).With(logkey.ZkPath, path) logger.Log("Reregistering watch") _, _, _, err := back.conn.ExistsW(path) if err != nil { logger.Log(log.Err, err, "Unable to reregistering watch") return errors.Annotatef(err, "unable to reregister watch for node %s", path) } return nil }
// Duration returns a duration object that calls ParseDuration() on the given key func (c *Distconf) Duration(key string, defaultVal time.Duration) *Duration { s := &durationConf{ defaultVal: defaultVal, Duration: Duration{ currentVal: defaultVal.Nanoseconds(), }, logger: log.NewContext(c.Logger).With(logkey.DistconfKey, key), } // Note: in race conditions 's' may not be the thing actually returned ret, okCast := c.register(key, s).(*durationConf) if !okCast { c.Logger.Log(logkey.DistconfKey, key, "Registering key with multiple types! FIX ME!!!!") return nil } return &ret.Duration }
func (back *zkConfig) refreshWatches(functionLogger log.Logger) { for path, callbacks := range back.callbacks.copy() { pathLogger := log.NewContext(functionLogger).With(logkey.ZkPath, path) for _, c := range callbacks { c(path) } for { err := back.reregisterWatch(path, pathLogger) if err == nil { break } pathLogger.Log(log.Err, err, "Error reregistering watch") time.Sleep(back.refreshDelay.get()) } } }
// Zk creates a zookeeper readable backing func Zk(zkConnector ZkConnector, conf *ZkConfig) (ReaderWriter, error) { conf = pointer.FillDefaultFrom(conf, DefaultZkConfig).(*ZkConfig) ret := &zkConfig{ rootLogger: log.NewContext(conf.Logger).With(logkey.DistconfBacking, "zk"), shouldQuit: make(chan struct{}), callbacks: callbackMap{ callbacks: make(map[string][]backingCallbackFunction), }, refreshDelay: atomicDuration{ refreshRetryDelay: time.Millisecond * 500, }, } var err error ret.conn, ret.eventChan, err = zkConnector.Connect() if err != nil { return nil, errors.Annotate(err, "cannot create zk connection") } go ret.drainEventChan(conf.Logger) return ret, nil }
func (back *zkConfig) drainEventChan(functionLogger log.Logger) { drainContext := log.NewContext(functionLogger).With(logkey.Func, "drainEventChan") defer drainContext.Log("Draining done") for { drainContext.Log("Blocking with event") select { case e := <-back.eventChan: eventContext := drainContext.With(logkey.ZkEvent, e) eventContext.Log("event seen") back.logInfoState(eventContext, e) if e.State == zk.StateHasSession { eventContext.Log("Server now has a session.") back.refreshWatches(eventContext) continue } if e.Path == "" { continue } if len(e.Path) > 0 && e.Path[0] == '/' { e.Path = e.Path[1:] } { eventContext.Log(logkey.ArrLen, back.callbacks.len(), "change state") for _, c := range back.callbacks.get(e.Path) { c(e.Path) } } eventContext.Log("reregistering watch") // Note: return value currently ignored. Not sure what to do about it back.reregisterWatch(e.Path, eventContext) eventContext.Log("reregistering watch finished") case <-back.shouldQuit: drainContext.Log("quit message seen") return } } }