package discovery import ( "context" "encoding/json" "fmt" clientv3 "go.etcd.io/etcd/client/v3" "go.etcd.io/etcd/client/v3/naming/endpoints" "sonet/pkg/utils/logger" "sonet/pkg/utils/shutdown" "time" ) func EtcdDialUrl(serviceName string) string { return fmt.Sprintf("etcd:///%s", serviceName) } func EtcdRegistry(client *clientv3.Client, server *Server) (err error) { em, err := endpoints.NewManager(client, server.Name) if err != nil { return } ip, port, err := RegisterIpPort(server.Addr) if err != nil { return } server.Addr = fmt.Sprintf("%s:%d", ip, port) // 序列化 metadata 信息 meta := "{}" if server.Attrs != nil { bytes, e := json.Marshal(server.Attrs) if e != nil { err = e return } meta = string(bytes) } ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() lease, err := client.Grant(ctx, DefaultRegisterTTL) // 使用租约注册端点确保如果主机无法维持保活心跳, 从服务中删除 if err != nil { return } endpointKey := fmt.Sprintf("%s/%s", server.Name, ip) err = em.AddEndpoint(ctx, endpointKey, endpoints.Endpoint{ Addr: server.Addr, Metadata: meta, }, clientv3.WithLease(lease.ID), ) // keepalive lease keepAliveCh, err := client.KeepAlive(context.Background(), lease.ID) doneCh := make(chan bool) c := func() { doneCh <- true <-doneCh } shutdown.AddShutdownHook(c) go func() { for { select { case <-doneCh: // async... not done logger.Info("keepalive done") ctx, c := context.WithTimeout(context.Background(), time.Second*5) _, _ = client.Revoke(ctx, lease.ID) c() doneCh <- true return case _ = <-keepAliveCh: } } }() return }