func StartHeartbeats(localIp string, ttl time.Duration, config *config.Config, storeAdapter storeadapter.StoreAdapter, logger *gosteno.Logger) (stopChan chan (chan bool)) { if len(config.EtcdUrls) == 0 { return } if storeAdapter == nil { panic("store adapter is nil") } logger.Debugf("Starting Health Status Updates to Store: /healthstatus/doppler/%s/%s/%d", config.Zone, config.JobName, config.Index) status, stopChan, err := storeAdapter.MaintainNode(storeadapter.StoreNode{ Key: fmt.Sprintf("/healthstatus/doppler/%s/%s/%d", config.Zone, config.JobName, config.Index), Value: []byte(localIp), TTL: uint64(ttl.Seconds()), }) if err != nil { panic(err) } go func() { for stat := range status { logger.Debugf("Health updates channel pushed %v at time %v", stat, time.Now()) } }() return stopChan }
func Announce(localIP string, ttl time.Duration, config *config.Config, storeAdapter storeadapter.StoreAdapter, logger *gosteno.Logger) chan (chan bool) { dopplerMetaBytes, err := buildDopplerMeta(localIP, config) if err != nil { panic(err) } key := fmt.Sprintf("%s/%s/%s/%d", META_ROOT, config.Zone, config.JobName, config.Index) logger.Debugf("Starting Health Status Updates to Store: %s", key) node := storeadapter.StoreNode{ Key: key, Value: dopplerMetaBytes, TTL: uint64(ttl.Seconds()), } // Call to create to make sure node is created before we return storeAdapter.Create(node) status, stopChan, err := storeAdapter.MaintainNode(node) if err != nil { panic(err) } // The status channel needs to be drained to maintain the node within the etcd cluster go func() { for stat := range status { logger.Debugf("Health updates channel pushed %v at time %v", stat, time.Now()) } }() return stopChan }
func AnnounceLegacy(localIP string, ttl time.Duration, config *config.Config, storeAdapter storeadapter.StoreAdapter, logger *gosteno.Logger) chan (chan bool) { key := fmt.Sprintf("%s/%s/%s/%d", LEGACY_ROOT, config.Zone, config.JobName, config.Index) status, stopChan, err := storeAdapter.MaintainNode(storeadapter.StoreNode{ Key: key, Value: []byte(localIP), TTL: uint64(ttl.Seconds()), }) if err != nil { panic(err) } // The status channel needs to be drained to maintain the node within the etcd cluster go func() { for stat := range status { logger.Debugf("Health updates channel pushed %v at time %v", stat, time.Now()) } }() return stopChan }
func Daemonize( component string, callback func() error, period time.Duration, timeout time.Duration, logger logger.Logger, adapter storeadapter.StoreAdapter, ) error { logger.Info("Acquiring lock for " + component) lock := storeadapter.StoreNode{ Key: "/hm/locks/" + component, TTL: 10, } lostLockChannel, releaseLockChannel, err := adapter.MaintainNode(lock) if err != nil { logger.Info(fmt.Sprintf("Failed to acquire lock: %s", err)) return err } go func() { <-lostLockChannel logger.Error("Lost the lock", errors.New("Lock the lock")) os.Exit(197) }() logger.Info("Acquired lock for " + component) logger.Info(fmt.Sprintf("Running Daemon every %d seconds with a timeout of %d", int(period.Seconds()), int(timeout.Seconds()))) for { afterChan := time.After(period) timeoutChan := time.After(timeout) errorChan := make(chan error, 1) t := time.Now() go func() { errorChan <- callback() }() select { case err := <-errorChan: logger.Info("Daemonize Time", map[string]string{ "Component": component, "Duration": fmt.Sprintf("%.4f", time.Since(t).Seconds()), }) if err != nil { logger.Error("Daemon returned an error. Continuining...", err) } case <-timeoutChan: released := make(chan bool) releaseLockChannel <- released <-released return errors.New("Daemon timed out. Aborting!") } <-afterChan } return nil }