func (s *DefaultSubscriber) Connect() error { consumer, err := nsqlib.NewConsumer(s.topic, s.channel, s.cfg) if err != nil { return err } consumer.SetLogger(&logBridge{}, nsqlib.LogLevelInfo) for _, handler := range s.handlers { consumer.AddHandler(handler) } s.consumer = consumer go s.configLoop() return nil }
// NewServiceLoader returns a loader that reads config from config service func NewServiceLoader(c *Config, addr, service, region, env string) (*Loader, error) { // define our hierarchy: // H2:BASE // H2:BASE:<service-name> // H2:REGION:<aws region> // H2:REGION:<aws region>:<service-name> // H2:ENV:<env> // H2:ENV:<env>:<service-name> hierarchy := []string{ "H2:BASE", fmt.Sprintf("H2:BASE:%s", service), fmt.Sprintf("H2:REGION:%s", region), fmt.Sprintf("H2:REGION:%s:%s", region, service), fmt.Sprintf("H2:ENV:%s", env), fmt.Sprintf("H2:ENV:%s:%s", env, service), } // construct URL if !strings.Contains(addr, "://") { addr = "https://" + addr } addr = strings.TrimRight(addr, "/") + "/compile" u, err := url.Parse(addr) if err != nil { return nil, fmt.Errorf("Failed to parse config service address: %v", err) } q := u.Query() q.Set("ids", strings.Join(hierarchy, ",")) u.RawQuery = q.Encode() configUrl := u.String() log.Infof("[Config] Initialising service loader for service '%s' in region '%s' in '%s' environment via URL %s", service, region, env, configUrl) rdr := func() (io.ReadCloser, error) { rsp, err := http.Get(configUrl) if err != nil { log.Errorf("[Config] Failed to load config via %s: %v", configUrl, err) return nil, fmt.Errorf("Failed to load config via %s: %v", configUrl, err) } defer rsp.Body.Close() if rsp.StatusCode != 200 { log.Errorf("[Config] Failed to load config via %s - status code %v", configUrl, rsp.StatusCode) return nil, fmt.Errorf("Failed to load config via %s - status code %v", configUrl, rsp.StatusCode) } b, _ := ioutil.ReadAll(rsp.Body) loaded := make(map[string]interface{}) err = json.Unmarshal(b, &loaded) if err != nil { log.Errorf("[Config] Unable to unmarshal loaded config: %v", err) return nil, fmt.Errorf("Unable to unmarshal loaded config: %v", err) } b, err = json.Marshal(loaded["config"]) if err != nil { log.Errorf("[Config] Unable to unmarshal loaded config: %v", err) return nil, fmt.Errorf("Unable to unmarshal loaded config: %v", err) } rdr := ioutil.NopCloser(bytes.NewReader(b)) return rdr, nil } changesChan := make(chan bool) l := NewLoader(c, changesChan, rdr) go func() { // wait until loaded l.reload() // look out for config changes PUBbed via NSQ -- subscribe via a random ephemeral channel channel := fmt.Sprintf("g%v#ephemeral", rand.Uint32()) consumer, err := nsqlib.NewConsumer("config.reload", channel, nsqlib.NewConfig()) if err != nil { log.Warnf("[Config] Failed to create NSQ reader to pickup config changes (fast reload disabled): ch=%v %v", channel, err) return } consumer.AddHandler(nsqlib.HandlerFunc(func(m *nsqlib.Message) error { changesChan <- true return nil })) // now configure it -- NOT via lookupd! There is a bug we think! subHosts := AtPath("hailo", "service", "nsq", "subHosts").AsHostnameArray(4150) if len(subHosts) == 0 { log.Warnf("[Config] No subHosts defined for config.reload topic (fast reload disabled)") return } log.Infof("[Config Load] Subscribing to config.reload (for fast config reloads) via NSQ hosts: %v", subHosts) if err := consumer.ConnectToNSQDs(subHosts); err != nil { log.Warnf("[Config Load] Failed to connect to NSQ for config changes (fast reload disabled): %v", err) return } // Wait for the Loader to be killed, and then stop the NSQ reader l.Wait() consumer.Stop() }() return l, nil }