mycommon/myregistry/consul/consul.go

154 lines
3.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package consul
import (
"fmt"
"git.makemake.in/kzkzzzz/mycommon/myconf"
"git.makemake.in/kzkzzzz/mycommon/myregistry"
"github.com/google/uuid"
api "github.com/hashicorp/consul/api"
"log"
"net"
"net/url"
"time"
)
var _ myregistry.IRegister = (*Consul)(nil)
type Consul struct {
client *api.Client
serviceIds map[string][]string
serviceTags []string
}
func (c *Consul) Name() string {
return "consul"
}
func (c *Consul) Register(service *myregistry.ServiceInfo) error {
// 健康检查
serviceId := uuid.New().String()
c.serviceIds[service.ServiceName] = append(c.serviceIds[service.ServiceName], serviceId)
check := &api.AgentServiceCheck{
CheckID: serviceId,
TCP: fmt.Sprintf("%s:%d", service.Ip, service.Port),
Timeout: "5s", // 超时时间
Interval: "20s", // 运行检查的频率
// 指定时间后自动注销不健康的服务节点
// 最小超时时间为1分钟收获不健康服务的进程每30秒运行一次因此触发注销的时间可能略长于配置的超时时间。
DeregisterCriticalServiceAfter: "5m",
Status: "passing",
}
srv := &api.AgentServiceRegistration{
ID: serviceId, // 服务唯一ID
Name: service.ServiceName, // 服务名称
Tags: c.serviceTags, // 为服务打标签
Address: service.Ip,
Port: service.Port,
Check: check,
}
return c.client.Agent().ServiceRegister(srv)
}
func (c *Consul) Deregister(service *myregistry.ServiceInfo) error {
for _, svcId := range c.serviceIds[service.ServiceName] {
err := c.client.Agent().ServiceDeregister(svcId)
if err != nil {
log.Printf("Failed to deregister service %s: %s\n", service, err)
}
}
return nil
}
type Conf struct {
Addr string
Token string
}
func MustNew(conf *myconf.Config) *Consul {
consul, err := New(conf)
if err != nil {
panic(err)
}
return consul
}
func New(conf *myconf.Config) (*Consul, error) {
cfg := api.DefaultConfig()
cfg.Address = conf.GetString("addr")
cfg.Transport.DialContext = (&net.Dialer{
Timeout: 3 * time.Second,
KeepAlive: 20 * time.Second,
DualStack: true,
}).DialContext
cfg.Token = conf.GetString("token")
username := conf.GetString("username")
password := conf.GetString("password")
if username != "" && password != "" {
cfg.HttpAuth = &api.HttpBasicAuth{
Username: username,
Password: password,
}
}
client, err := api.NewClient(cfg)
if err != nil {
return nil, err
}
cl := &Consul{
client: client,
serviceIds: make(map[string][]string),
serviceTags: make([]string, 0),
}
if v := conf.GetStringSlice("serviceTags"); len(v) > 0 {
cl.serviceTags = v
} else {
cl.serviceTags = []string{}
}
return cl, nil
}
func (c *Consul) Client() *api.Client {
return c.client
}
func GrpcUrl(serviceName string, conf *myconf.Config) string {
return GrpcUrlWithTag("", serviceName, conf)
}
func GrpcUrlWithTag(tag string, serviceName string, conf *myconf.Config) string {
u := &url.URL{
Scheme: schemeName,
Host: conf.GetString("addr"),
Path: serviceName,
}
query := u.Query()
query.Set("healthy", "true")
if v := conf.GetString("token"); v != "" {
query.Set("token", v)
}
if tag != "" {
query.Set("tag", tag)
}
username := conf.GetString("username")
password := conf.GetString("password")
if username != "" && password != "" {
u.User = url.UserPassword(username, password)
}
u.RawQuery = query.Encode()
return u.String()
}