Files
goLearn/user-server/main.go
2025-09-07 15:44:15 +08:00

145 lines
3.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"context"
"log"
"net"
"os"
"os/signal"
"syscall"
"time"
"go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/client/v3/naming/endpoints"
)
// UserServer 用户服务结构体
type UserServer struct{}
// Login 登录方法示例
func (u *UserServer) Login(username string, password string) string {
if username == "admin" && password == "123456" {
return "登录成功token: abc123"
}
return "登录失败,用户名或密码错误"
}
// 服务注册到etcd
func registerService(etcdAddr []string, serviceName, serviceAddr string) (*clientv3.Client, error) {
// 1. 创建etcd客户端返回客户端方便后续注销
client, err := clientv3.New(clientv3.Config{
Endpoints: etcdAddr,
DialTimeout: 5 * time.Second,
})
if err != nil {
return nil, err
}
// 2. 创建租约10秒有效期
leaseResp, err := client.Grant(context.Background(), 10)
if err != nil {
client.Close()
return nil, err
}
leaseID := leaseResp.ID
// 3. 启动租约续约
keepAliveChan, err := client.KeepAlive(context.Background(), leaseID)
if err != nil {
client.Revoke(context.Background(), leaseID) // 清理租约
client.Close()
return nil, err
}
// 后台处理续约结果
go func() {
for {
select {
case keepAliveResp, ok := <-keepAliveChan:
if !ok {
// 续约通道关闭,尝试重新连接
log.Println("租约续约通道关闭,尝试重新连接...")
return
}
log.Printf("服务续约成功租约ID: %v", keepAliveResp.ID)
}
}
}()
// 4. 注册服务到etcd
em, err := endpoints.NewManager(client, "/services/"+serviceName)
if err != nil {
client.Revoke(context.Background(), leaseID)
client.Close()
return nil, err
}
// 注册服务并绑定租约
err = em.AddEndpoint(
context.Background(),
"/services/"+serviceName+"/"+serviceAddr,
endpoints.Endpoint{Addr: serviceAddr},
clientv3.WithLease(leaseID),
)
if err != nil {
client.Revoke(context.Background(), leaseID)
client.Close()
return nil, err
}
return client, nil
}
// 从etcd注销服务
func unregisterService(client *clientv3.Client, serviceName, serviceAddr string) {
if client == nil {
return
}
defer client.Close()
em, err := endpoints.NewManager(client, "/services/"+serviceName)
if err != nil {
log.Printf("注销服务失败: %v", err)
return
}
// 主动删除服务节点
err = em.DeleteEndpoint(context.Background(), "/services/"+serviceName+"/"+serviceAddr)
if err != nil {
log.Printf("删除服务节点失败: %v", err)
} else {
log.Println("服务已从etcd注销")
}
}
func main() {
// 服务配置
etcdAddr := []string{"http://127.0.0.1:2379"}
serviceName := "user-service"
serviceAddr := "127.0.0.1:8080" // 服务监听地址
// 注册服务到etcd
etcdClient, err := registerService(etcdAddr, serviceName, serviceAddr)
if err != nil {
log.Fatalf("服务注册失败: %v", err)
}
log.Printf("服务 %s 已注册到etcd地址: %s", serviceName, serviceAddr)
// 启动一个实际的服务监听例如TCP服务避免程序立即退出
listener, err := net.Listen("tcp", serviceAddr)
if err != nil {
log.Fatalf("服务监听失败: %v", err)
}
defer listener.Close()
log.Printf("服务已启动,监听地址: %s", serviceAddr)
// 优雅退出处理(捕获中断信号,注销服务)
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
<-sigChan // 等待中断信号
// 程序退出前注销服务
unregisterService(etcdClient, serviceName, serviceAddr)
log.Println("服务已停止")
}