github.com/godaddy-x/freego@v1.0.156/rpcx/consulx.go (about)

     1  package rpcx
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/godaddy-x/freego/cache"
     6  	DIC "github.com/godaddy-x/freego/common"
     7  	"github.com/godaddy-x/freego/utils"
     8  	"github.com/godaddy-x/freego/zlog"
     9  	consulapi "github.com/hashicorp/consul/api"
    10  	"go.uber.org/zap"
    11  	"net/http"
    12  	"time"
    13  )
    14  
    15  var (
    16  	consulSessions = make(map[string]*ConsulManager, 0)
    17  	consulSlowlog  *zap.Logger
    18  	queryOptions   = &consulapi.QueryOptions{
    19  		UseCache:     true,
    20  		MaxAge:       7200 * time.Second,
    21  		StaleIfError: 14400 * time.Second,
    22  	}
    23  )
    24  
    25  const (
    26  	DefaultConsulDockerHost = "172.17.0.1:8500"
    27  	DefaultConsulLocalHost  = "127.0.0.1:8500"
    28  	DefaultConsulDomainHost = "consulx.com:8500"
    29  )
    30  
    31  type ConsulManager struct {
    32  	Host    string
    33  	Token   string
    34  	Consulx *consulapi.Client
    35  	Config  *ConsulConfig
    36  }
    37  
    38  // Consulx配置参数
    39  type ConsulConfig struct {
    40  	DsName       string // 数据源名
    41  	Host         string // consul host
    42  	CheckPort    int    // 健康监测端口
    43  	RpcPort      int    // RPC调用端口
    44  	Protocol     string // RPC协议, tcp
    45  	Timeout      string // 请求超时时间, 3s
    46  	Interval     string // 健康监测时间, 5s
    47  	DestroyAfter string // 销毁服务时间, 600s
    48  	CheckPath    string // 健康检测path /xxx/check
    49  	LogPath      string // 日志输出路径
    50  	SlowQuery    int64  // 0.不开启筛选 >0开启筛选查询 毫秒
    51  	SlowLogPath  string // 慢查询写入地址
    52  }
    53  
    54  func getConsulClient(conf ConsulConfig) *ConsulManager {
    55  	config := consulapi.DefaultConfig()
    56  	config.Address = conf.Host
    57  	client, err := consulapi.NewClient(config)
    58  	if err != nil {
    59  		panic(utils.AddStr("consul [", conf.Host, "] init failed: ", err))
    60  	}
    61  	return &ConsulManager{Consulx: client, Host: conf.Host}
    62  }
    63  
    64  func (self *ConsulManager) InitConfig(input ...ConsulConfig) (*ConsulManager, error) {
    65  	for _, conf := range input {
    66  		if len(conf.Host) == 0 {
    67  			panic("consul host is nil")
    68  		}
    69  		if len(conf.DsName) == 0 {
    70  			conf.DsName = DIC.MASTER
    71  		}
    72  		manager := getConsulClient(conf)
    73  		manager.Config = &conf
    74  		consulSessions[manager.Config.DsName] = manager
    75  		manager.initSlowLog()
    76  		zlog.Printf("consul service %s【%s】has been started successful", conf.Host, conf.DsName)
    77  	}
    78  	if len(consulSessions) == 0 {
    79  		zlog.Printf("consul init failed: sessions is nil")
    80  	}
    81  	return self, nil
    82  }
    83  
    84  func InitDefaultConsul() {
    85  	config := ConsulConfig{Host: DefaultConsulDockerHost}
    86  	if _, err := new(ConsulManager).InitConfig(config); err != nil {
    87  		panic(err)
    88  	}
    89  }
    90  
    91  func InitHostConsul(host string) {
    92  	config := ConsulConfig{Host: host}
    93  	if _, err := new(ConsulManager).InitConfig(config); err != nil {
    94  		panic(err)
    95  	}
    96  }
    97  
    98  func NewConsul(ds ...string) (*ConsulManager, error) {
    99  	return new(ConsulManager).Client(ds...)
   100  }
   101  
   102  func (self *ConsulManager) initSlowLog() {
   103  	if self.Config.SlowQuery == 0 || len(self.Config.SlowLogPath) == 0 {
   104  		return
   105  	}
   106  	if consulSlowlog == nil {
   107  		consulSlowlog = zlog.InitNewLog(&zlog.ZapConfig{
   108  			Level:   "warn",
   109  			Console: false,
   110  			FileConfig: &zlog.FileConfig{
   111  				Compress:   true,
   112  				Filename:   self.Config.SlowLogPath,
   113  				MaxAge:     7,
   114  				MaxBackups: 7,
   115  				MaxSize:    512,
   116  			}})
   117  		fmt.Println("consul monitoring service started successful...")
   118  	}
   119  }
   120  
   121  func (self *ConsulManager) GetSlowLog() *zap.Logger {
   122  	return consulSlowlog
   123  }
   124  
   125  func (self *ConsulManager) Client(ds ...string) (*ConsulManager, error) {
   126  	dsName := DIC.MASTER
   127  	if len(ds) > 0 && len(ds[0]) > 0 {
   128  		dsName = ds[0]
   129  	}
   130  	manager := consulSessions[dsName]
   131  	if manager == nil {
   132  		return nil, utils.Error("consul session [", ds, "] not found...")
   133  	}
   134  	return manager, nil
   135  }
   136  
   137  // 通过Consul中心获取指定JSON配置数据
   138  func (self *ConsulManager) GetJsonValue(key string, result interface{}) error {
   139  	client := self.Consulx
   140  	kv := client.KV()
   141  	if kv == nil {
   142  		return utils.Error("consul node [", key, "] not found...")
   143  	}
   144  	k, _, err := kv.Get(key, nil)
   145  	if err != nil {
   146  		return utils.Error("consul node [", key, "] read failed...")
   147  	}
   148  	if k == nil || k.Value == nil || len(k.Value) == 0 {
   149  		return utils.Error("consul node [", key, "] read is nil...")
   150  	}
   151  	if err := utils.JsonUnmarshal(k.Value, result); err != nil {
   152  		return utils.Error("consul node [", key, "] parse failed...")
   153  	}
   154  	return nil
   155  }
   156  
   157  // 通过Consul中心获取指定加密JSON配置数据
   158  func (self *ConsulManager) GetAesJsonValue(key, encKey string, result interface{}) error {
   159  	client := self.Consulx
   160  	kv := client.KV()
   161  	if kv == nil {
   162  		return utils.Error("consul node [", key, "] not found...")
   163  	}
   164  	k, _, err := kv.Get(key, nil)
   165  	if err != nil {
   166  		return utils.Error("consul node [", key, "] read failed...")
   167  	}
   168  	if k == nil || k.Value == nil || len(k.Value) == 0 {
   169  		return utils.Error("consul node [", key, "] read is nil...")
   170  	}
   171  	bts, err := utils.AesDecrypt(utils.Bytes2Str(k.Value), encKey, encKey)
   172  	if err != nil {
   173  		return err
   174  	}
   175  	if err := utils.JsonUnmarshal(bts, result); err != nil {
   176  		return utils.Error("consul node [", key, "] parse failed...")
   177  	}
   178  	return nil
   179  }
   180  
   181  func (self *ConsulManager) GetTextValue(key string) ([]byte, error) {
   182  	client := self.Consulx
   183  	kv := client.KV()
   184  	if kv == nil {
   185  		return nil, utils.Error("consul node [", key, "] not found...")
   186  	}
   187  	k, _, err := kv.Get(key, nil)
   188  	if err != nil {
   189  		return nil, utils.Error("consul node [", key, "] read failed...")
   190  	}
   191  	if k == nil || k.Value == nil || len(k.Value) == 0 {
   192  		return nil, utils.Error("consul node [", key, "] read is nil...")
   193  	}
   194  	return k.Value, nil
   195  }
   196  
   197  func (self *ConsulManager) RemoveService(serviceIDs ...string) {
   198  	services, err := self.Consulx.Agent().Services()
   199  	if err != nil {
   200  		panic(err)
   201  	}
   202  	if len(serviceIDs) > 0 {
   203  		for _, v := range services {
   204  			for _, ID := range serviceIDs {
   205  				if ID == v.ID {
   206  					if err := self.Consulx.Agent().ServiceDeregister(v.ID); err != nil {
   207  						zlog.Println(err)
   208  					}
   209  					zlog.Println("remove grpc service successful: ", v.Service, " - ", v.ID)
   210  				}
   211  			}
   212  		}
   213  		return
   214  	}
   215  	for _, v := range services {
   216  		if err := self.Consulx.Agent().ServiceDeregister(v.ID); err != nil {
   217  			zlog.Println(err)
   218  		}
   219  		zlog.Println("remove grpc service successful: ", v.Service, " - ", v.ID)
   220  	}
   221  }
   222  
   223  // 根据服务名获取可用列表
   224  func (self *ConsulManager) GetAllService(service string) ([]*consulapi.AgentService, error) {
   225  	result := make([]*consulapi.AgentService, 0)
   226  	services, err := self.Consulx.Agent().Services()
   227  	if err != nil {
   228  		return result, err
   229  	}
   230  	if len(service) == 0 {
   231  		for _, v := range services {
   232  			result = append(result, v)
   233  		}
   234  		return result, nil
   235  	}
   236  	for _, v := range services {
   237  		if service == v.Service {
   238  			result = append(result, v)
   239  		}
   240  	}
   241  	return result, nil
   242  }
   243  
   244  var localCache = cache.NewLocalCache(30, 5)
   245  
   246  func (self *ConsulManager) GetHealthService(service, tag string) ([]*consulapi.ServiceEntry, error) {
   247  	serviceEntry, _, err := self.Consulx.Health().Service(service, tag, false, queryOptions)
   248  	if err != nil {
   249  		return nil, err
   250  	}
   251  	if len(serviceEntry) == 0 {
   252  		return nil, utils.Error("no available services found: [", service, "]")
   253  	}
   254  	return serviceEntry, nil
   255  }
   256  
   257  func (self *ConsulManager) GetCacheService(service, tag string, cacheSecond int) ([]*consulapi.ServiceEntry, error) {
   258  	if cacheSecond <= 0 {
   259  		return self.GetHealthService(service, tag)
   260  	}
   261  	cvl, has, err := localCache.Get("consul.grpc."+service+"."+tag, nil)
   262  	if err != nil {
   263  		return nil, err
   264  	}
   265  	if has && cvl != nil {
   266  		return cvl.([]*consulapi.ServiceEntry), nil
   267  	}
   268  	serviceEntry, err := self.GetHealthService(service, tag)
   269  	if err != nil {
   270  		return nil, err
   271  	}
   272  	if err := localCache.Put("consul.grpc."+service+"."+tag, serviceEntry, cacheSecond); err != nil {
   273  		return nil, err
   274  	}
   275  	return serviceEntry, nil
   276  }
   277  
   278  func (self *ConsulManager) CheckService(services []*consulapi.AgentService, srvName, addr string) bool {
   279  	for _, v := range services {
   280  		if v.Service == srvName && v.Address == addr {
   281  			return true
   282  		}
   283  	}
   284  	return false
   285  }
   286  
   287  // 接口服务健康检查
   288  func (self *ConsulManager) HealthCheck(w http.ResponseWriter, r *http.Request) {
   289  	if _, err := fmt.Fprintln(w, "consulCheck"); err != nil {
   290  		zlog.Error("consul check output failed", 0, zlog.AddError(err))
   291  	}
   292  }