package consul import ( "encoding/json" "finclip-app-manager/infrastructure/config" "fmt" "net" "net/http" "strconv" "time" consulapi "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/api/watch" uuid "github.com/satori/go.uuid" ) var ( mopConsul *MopConsul ) type MopConsul struct { CheckPort string NodeId string ConsulClient *consulapi.Client IsRegSucc bool IsStop bool } func InitConsul() { mopConsul = NewMopConsul() mopConsul.Init() } func GetConsulInstance() *MopConsul { return mopConsul } func NewMopConsul() *MopConsul { var m MopConsul m.CheckPort = "9091" m.NodeId = uuid.NewV4().String() m.IsRegSucc = false m.IsStop = false var err error cfg := consulapi.DefaultConfig() cfg.Address = config.GetConfig().ConsulAddr m.ConsulClient, err = consulapi.NewClient(cfg) if err != nil { panic(err) } return &m } func (m *MopConsul) Init() { m.InitCheck() //初始化check接口 time.Sleep(1 * time.Second) m.RegisterServer() //注册服务 go m.WatchService() //服务是否发生change go m.SyncServiceHealth(60) //主动拉取健康状态 } func (m *MopConsul) InitCheck() { http.HandleFunc("/"+m.NodeId+"/check", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("success")) }) go http.ListenAndServe(":"+m.CheckPort, nil) } func (m *MopConsul) GetLocalIP() string { addrs, err := net.InterfaceAddrs() if err != nil { return "" } for _, address := range addrs { if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { if ipnet.IP.To4() != nil { return ipnet.IP.String() } } } return "" } func (m *MopConsul) RegisterServer() { if m.IsStop { return } registration := new(consulapi.AgentServiceRegistration) registration.ID = m.NodeId registration.Name = config.GetConfig().ServerName registration.Port, _ = strconv.Atoi(config.GetConfig().GrpcPort) registration.Tags = []string{config.GetConfig().ConsulTag} registration.Address = m.GetLocalIP() fmt.Println("localIP=" + registration.Address) registration.Check = &consulapi.AgentServiceCheck{ CheckID: m.NodeId, HTTP: "http://" + registration.Address + ":" + m.CheckPort + "/" + m.NodeId + "/check", Timeout: "5s", Interval: "30s", DeregisterCriticalServiceAfter: "35s", //check失败后35秒删除本服务 } err := m.ConsulClient.Agent().ServiceRegister(registration) if err != nil { fmt.Errorf("ServiceRegister err:" + err.Error()) if m.IsRegSucc == false { panic(err) } } m.IsRegSucc = true fmt.Println("Consul RegisterServer success") } func (m *MopConsul) DisRegisterServer() { m.IsStop = true err := m.ConsulClient.Agent().ServiceDeregister(m.NodeId) if err != nil { fmt.Errorf("ServiceDeregister service:%s err:%s\n", m.NodeId, err.Error()) } else { fmt.Printf("ServiceDeregister service:%s succ\n", m.NodeId) } } func (m *MopConsul) WatchService() { var notifyCh = make(chan struct{}) watchContent := `{"type":"service", "service":"` + config.GetConfig().ServerName + `", "tag":"` + config.GetConfig().ConsulTag + `"}` plan := m.WatchParse(watchContent) plan.Handler = func(idx uint64, raw interface{}) { fmt.Println("service change...") if raw == nil { return // ignore } fmt.Println("do something...") notifyCh <- struct{}{} } go func() { if err := plan.Run(config.GetConfig().ConsulAddr); err != nil { panic(err) } }() defer plan.Stop() for { select { case <-notifyCh: m.RegisterAgain() } } } func (m *MopConsul) SyncServiceHealth(gap int) { for { if m.IsStop { break } time.Sleep(time.Duration(gap) * time.Second) isHealth := false services, _, err := m.ConsulClient.Health().Service(config.GetConfig().ServerName, config.GetConfig().ConsulTag, true, &consulapi.QueryOptions{WaitIndex: 0}) if err != nil { fmt.Errorf("error retrieving instances from Consul: %s", err.Error()) } for _, s := range services { if s.Service.ID == m.NodeId { isHealth = true break } } if !isHealth { m.RegisterServer() } } } func (m *MopConsul) WatchParse(q string) *watch.Plan { var params map[string]interface{} if err := json.Unmarshal([]byte(q), ¶ms); err != nil { fmt.Errorf("Unmarshal err:" + err.Error()) return nil } plan, err := watch.Parse(params) if err != nil { panic(err) } return plan } func (m *MopConsul) RegisterAgain() { if !m.CheckServiceIsOK() { m.RegisterServer() } } func (m *MopConsul) CheckServiceIsOK() bool { services, _ := m.ConsulClient.Agent().Services() isOK := false if len(services) > 0 { if value, ok := services[m.NodeId]; ok { if value.Service == config.GetConfig().ServerName { if value.Weights.Passing == 1 { isOK = true } } } } return isOK }