221 lines
4.8 KiB
Go
221 lines
4.8 KiB
Go
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
|
|
}
|