feat: 添加基于Consul的RPC客户端和服务端
This commit is contained in:
69
rpc/client.go
Normal file
69
rpc/client.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
consulClient "github.com/rpcxio/rpcx-consul/client"
|
||||
"github.com/smallnest/rpcx/client"
|
||||
)
|
||||
|
||||
var (
|
||||
xclientMap = make(map[string]client.XClient)
|
||||
xclientMu sync.RWMutex
|
||||
)
|
||||
|
||||
// CallWithConsul 基于Consul服务发现调用RPC
|
||||
func CallWithConsul(ctx context.Context, serviceName string, args, reply interface{}) error {
|
||||
xclient, err := getOrCreatXClient(serviceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = xclient.Call(ctx, "Mul", args, reply)
|
||||
if err != nil {
|
||||
// 调用失败,清理失效客户端
|
||||
removeXClient(serviceName)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func removeXClient(serviceName string) {
|
||||
xclientMu.Lock()
|
||||
defer xclientMu.Unlock()
|
||||
if c, ok := xclientMap[serviceName]; ok {
|
||||
c.Close()
|
||||
delete(xclientMap, serviceName)
|
||||
}
|
||||
}
|
||||
|
||||
func getOrCreatXClient(serviceName string) (client.XClient, error) {
|
||||
// 第一次:读锁,快速判断是否存在
|
||||
xclientMu.RLock()
|
||||
if c, ok := xclientMap[serviceName]; ok {
|
||||
xclientMu.RUnlock()
|
||||
return c, nil
|
||||
}
|
||||
xclientMu.RUnlock()
|
||||
|
||||
// 没找到,加写锁准备创建
|
||||
xclientMu.Lock()
|
||||
defer xclientMu.Unlock()
|
||||
|
||||
// 第二次:双重检查,防止刚被别人创建完
|
||||
if c, ok := xclientMap[serviceName]; ok {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
consulAddr := g.Cfg().MustGet(nil, "consul.address").String()
|
||||
|
||||
d, err := consulClient.NewConsulDiscovery("rpcx", serviceName, []string{consulAddr}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := client.NewXClient(serviceName, client.Failtry, client.RandomSelect, d, client.DefaultOption)
|
||||
xclientMap[serviceName] = c
|
||||
return c, nil
|
||||
}
|
||||
93
rpc/server.go
Normal file
93
rpc/server.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/rpcxio/rpcx-consul/serverplugin"
|
||||
"github.com/smallnest/rpcx/server"
|
||||
)
|
||||
|
||||
var rpcServer *server.Server
|
||||
|
||||
// Serve 启动RPC服务
|
||||
func Serve(ctx context.Context, service interface{}) error {
|
||||
// 获取本机IP
|
||||
ip, err := getLocalIP()
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取IP失败: %w", err)
|
||||
}
|
||||
|
||||
// 解析端口
|
||||
addrConfig := g.Cfg().MustGet(ctx, "server.address").String()
|
||||
portStr := strings.TrimPrefix(addrConfig, ":")
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
return errors.New("端口解析失败")
|
||||
}
|
||||
serviceAddr := fmt.Sprintf("%s:%d", ip, port)
|
||||
|
||||
// 创建服务端
|
||||
rpcServer = server.NewServer()
|
||||
|
||||
// 添加 Consul 注册插件
|
||||
consulAddr := g.Cfg().MustGet(ctx, "consul.address").String()
|
||||
if consulAddr != "" {
|
||||
plugin := &serverplugin.ConsulRegisterPlugin{
|
||||
ServiceAddress: "tcp@" + serviceAddr,
|
||||
ConsulServers: []string{consulAddr},
|
||||
BasePath: "rpcx",
|
||||
UpdateInterval: time.Minute,
|
||||
}
|
||||
if err := plugin.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
rpcServer.Plugins.Add(plugin)
|
||||
g.Log().Infof(ctx, "Consul注册成功: %s", serviceAddr)
|
||||
}
|
||||
|
||||
// 注册服务
|
||||
err = rpcServer.Register(service, "")
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "注册服务失败: %v", err)
|
||||
return nil
|
||||
}
|
||||
// 优雅关闭
|
||||
//gproc.AddShutdownFunc(func(ctx context.Context) {
|
||||
// if rpcServer != nil {
|
||||
// _ = rpcServer.Shutdown(ctx)
|
||||
// }
|
||||
//})
|
||||
|
||||
// 异步启动
|
||||
go func() {
|
||||
g.Log().Infof(ctx, "RPC服务启动: %s", serviceAddr)
|
||||
if err := rpcServer.Serve("tcp", serviceAddr); err != nil {
|
||||
g.Log().Fatalf(ctx, "RPC服务启动失败: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getLocalIP() (string, error) {
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, addr := range addrs {
|
||||
if ipNet, ok := addr.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
|
||||
if ipNet.IP.To4() != nil {
|
||||
return ipNet.IP.String(), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("未找到本机IP")
|
||||
}
|
||||
Reference in New Issue
Block a user