配置文件从consul的配置中读取,监听配置文件改变的状态
This commit is contained in:
@@ -1,16 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcfg"
|
||||
"github.com/gogf/gf/v2/os/genv"
|
||||
)
|
||||
|
||||
func init() {
|
||||
env := genv.Get("APP_ENV", "").String()
|
||||
if env != "" {
|
||||
g.Cfg().GetAdapter().(*gcfg.AdapterFile).SetFileName(fmt.Sprintf("config-%s.yml", env))
|
||||
}
|
||||
}
|
||||
162
consul/consul.go
162
consul/consul.go
@@ -13,7 +13,11 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/gsel"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"github.com/gogf/gf/v2/os/gcfg"
|
||||
"github.com/gogf/gf/v2/os/genv"
|
||||
"github.com/gogf/gf/v2/util/grand"
|
||||
"github.com/hashicorp/consul/api"
|
||||
"github.com/r3labs/diff/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -135,7 +139,165 @@ func init() {
|
||||
// 连接成功后启动健康检查和自动重连
|
||||
go startHealthCheckAndReconnect()
|
||||
}
|
||||
|
||||
loadConfigFromConsul()
|
||||
}
|
||||
|
||||
func loadConfigFromConsul() {
|
||||
ctx := context.Background()
|
||||
|
||||
serviceName := g.Cfg().MustGet(ctx, "server.name", "admin-go").String()
|
||||
env := genv.Get("APP_ENV", "").String()
|
||||
fmt.Printf("服务名称: %s, 环境变量 APP_ENV: %s\n", serviceName, env)
|
||||
|
||||
if env == "" {
|
||||
fmt.Printf("未设置 APP_ENV 环境变量,跳过 Consul 配置加载\n")
|
||||
return
|
||||
}
|
||||
|
||||
consulData, lastIndex, err := loadEnvFromConsul(env, serviceName)
|
||||
if err == nil && len(consulData) > 0 {
|
||||
adapter, err := gcfg.NewAdapterContent()
|
||||
if err != nil {
|
||||
fmt.Printf("创建配置适配器失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
adapter.SetContent(string(consulData))
|
||||
g.Cfg().SetAdapter(adapter)
|
||||
|
||||
fmt.Printf("已从 Consul 成功加载初始配置\n")
|
||||
|
||||
go watchConsulConfig(env, serviceName, lastIndex)
|
||||
} else {
|
||||
fmt.Printf("从 Consul 获取配置失败,使用本地配置文件\n")
|
||||
}
|
||||
}
|
||||
|
||||
func loadEnvFromConsul(env string, serviceName string) ([]byte, uint64, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
consulAddress := g.Cfg().MustGet(ctx, "consul.address", "127.0.0.1:8500").String()
|
||||
fmt.Printf("Consul 地址: %s\n", consulAddress)
|
||||
|
||||
config := api.DefaultConfig()
|
||||
config.Address = consulAddress
|
||||
|
||||
client, err := api.NewClient(config)
|
||||
if err != nil {
|
||||
fmt.Printf("创建 Consul 客户端失败: %v\n", err)
|
||||
return nil, 0, err
|
||||
}
|
||||
consulKey := fmt.Sprintf("config/%s/%s-%s", serviceName, serviceName, env)
|
||||
fmt.Printf("从 Consul 读取配置键: %s\n", consulKey)
|
||||
|
||||
kv := client.KV()
|
||||
|
||||
opts := &api.QueryOptions{
|
||||
WaitIndex: 0,
|
||||
WaitTime: 60 * time.Second,
|
||||
}
|
||||
|
||||
pair, meta, err := kv.Get(consulKey, opts)
|
||||
if err != nil {
|
||||
fmt.Printf("从 Consul 读取配置失败: %v\n", err)
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if pair == nil {
|
||||
fmt.Printf("Consul 中未找到配置键: %s\n", consulKey)
|
||||
return nil, 0, nil
|
||||
}
|
||||
|
||||
fmt.Printf("已从 Consul 加载配置, Index: %d\n", meta.LastIndex)
|
||||
return pair.Value, meta.LastIndex, nil
|
||||
}
|
||||
|
||||
func watchConsulConfig(env string, serviceName string, lastIndex uint64) {
|
||||
ctx := context.Background()
|
||||
|
||||
consulAddress := g.Cfg().MustGet(ctx, "consul.address", "127.0.0.1:8500").String()
|
||||
config := api.DefaultConfig()
|
||||
config.Address = consulAddress
|
||||
|
||||
client, err := api.NewClient(config)
|
||||
if err != nil {
|
||||
fmt.Printf("创建 Consul 监听客户端失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
consulKey := fmt.Sprintf("config/%s/%s-%s", serviceName, serviceName, env)
|
||||
|
||||
for {
|
||||
opts := &api.QueryOptions{
|
||||
WaitIndex: lastIndex,
|
||||
WaitTime: 60 * time.Second,
|
||||
}
|
||||
|
||||
pair, meta, err := client.KV().Get(consulKey, opts)
|
||||
if err != nil {
|
||||
fmt.Printf("Consul 监听出错: %v, 5秒后重试...\n", err)
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
if meta.LastIndex == lastIndex {
|
||||
continue
|
||||
}
|
||||
|
||||
if pair == nil {
|
||||
fmt.Printf("Consul 配置被删除: %s\n", consulKey)
|
||||
lastIndex = meta.LastIndex
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("检测到 Consul 配置变更: %s, New Index: %d\n", consulKey, meta.LastIndex)
|
||||
|
||||
updateLocalConfig(pair.Value)
|
||||
|
||||
lastIndex = meta.LastIndex
|
||||
}
|
||||
}
|
||||
|
||||
func updateLocalConfig(content []byte) {
|
||||
ctx := context.Background()
|
||||
|
||||
oldConfig, _ := g.Cfg().Data(ctx)
|
||||
|
||||
adapter, err := gcfg.NewAdapterContent()
|
||||
if err != nil {
|
||||
fmt.Printf("创建新配置适配器失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
adapter.SetContent(string(content))
|
||||
g.Cfg().SetAdapter(adapter)
|
||||
|
||||
newConfig, _ := g.Cfg().Data(ctx)
|
||||
|
||||
changelog, err := diff.Diff(oldConfig, newConfig)
|
||||
if err != nil {
|
||||
fmt.Printf("配置对比失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(changelog) == 0 {
|
||||
fmt.Printf("配置已热更新成功(内容无实质变化)\n")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("=== 检测到配置变更 (%d 项) ===\n", len(changelog))
|
||||
for _, change := range changelog {
|
||||
switch change.Type {
|
||||
case "create":
|
||||
fmt.Printf("[+] 新增: %s = %v\n", change.Path, change.To)
|
||||
case "update":
|
||||
fmt.Printf("[~] 修改: %s: %v -> %v\n", change.Path, change.From, change.To)
|
||||
case "delete":
|
||||
fmt.Printf("[-] 删除: %s (原值: %v)\n", change.Path, change.From)
|
||||
}
|
||||
}
|
||||
fmt.Printf("=================================\n")
|
||||
}
|
||||
|
||||
func getLocalIP() (string, error) {
|
||||
// 获取本机所有网络接口
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
|
||||
6
go.mod
6
go.mod
@@ -10,11 +10,14 @@ require (
|
||||
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.9.5
|
||||
github.com/gogf/gf/v2 v2.9.5
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/hashicorp/consul/api v1.26.1
|
||||
github.com/meilisearch/meilisearch-go v0.36.1
|
||||
github.com/minio/minio-go/v7 v7.0.97
|
||||
github.com/nats-io/nats.go v1.48.0
|
||||
github.com/olivere/elastic/v7 v7.0.32
|
||||
github.com/r3labs/diff/v2 v2.15.1
|
||||
github.com/rabbitmq/amqp091-go v1.10.0
|
||||
github.com/rogpeppe/go-internal v1.13.1
|
||||
github.com/rpcxio/rpcx-consul v0.1.1
|
||||
github.com/smallnest/rpcx v1.9.1
|
||||
github.com/tiger1103/gfast-token v1.0.10
|
||||
@@ -67,7 +70,6 @@ require (
|
||||
github.com/grandcat/zeroconf v1.0.0 // indirect
|
||||
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
|
||||
github.com/hashicorp/consul/api v1.26.1 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-hclog v1.5.0 // indirect
|
||||
@@ -127,6 +129,7 @@ require (
|
||||
github.com/tklauser/numcpus v0.2.2 // indirect
|
||||
github.com/valyala/fastrand v1.1.0 // indirect
|
||||
github.com/vcaesar/cedar v0.30.0 // indirect
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
@@ -150,6 +153,7 @@ require (
|
||||
golang.org/x/sys v0.35.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
golang.org/x/tools v0.35.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
|
||||
google.golang.org/grpc v1.75.0 // indirect
|
||||
|
||||
8
go.sum
8
go.sum
@@ -507,6 +507,8 @@ github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/quic-go/quic-go v0.49.0 h1:w5iJHXwHxs1QxyBv1EHKuC50GX5to8mJAxvtnttJp94=
|
||||
github.com/quic-go/quic-go v0.49.0/go.mod h1:s2wDnmCdooUQBmQfpUSTCYBl1/D4FcqbULMMkASvR6s=
|
||||
github.com/r3labs/diff/v2 v2.15.1 h1:EOrVqPUzi+njlumoqJwiS/TgGgmZo83619FNDB9xQUg=
|
||||
github.com/r3labs/diff/v2 v2.15.1/go.mod h1:I8noH9Fc2fjSaMxqF3G2lhDdC0b+JXCfyx85tWFM9kc=
|
||||
github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw=
|
||||
github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
@@ -568,6 +570,7 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
@@ -597,6 +600,8 @@ github.com/vcaesar/cedar v0.30.0 h1:9fSDpM7FTjjUdPiBUUa0MWYMRGSEcqgFXvppZcZ4d7Y=
|
||||
github.com/vcaesar/cedar v0.30.0/go.mod h1:lyuGvALuZZDPNXwpzv/9LyxW+8Y6faN7zauFezNsnik=
|
||||
github.com/vcaesar/tt v0.20.1 h1:D/jUeeVCNbq3ad8M7hhtB3J9x5RZ6I1n1eZ0BJp7M+4=
|
||||
github.com/vcaesar/tt v0.20.1/go.mod h1:cH2+AwGAJm19Wa6xvEa+0r+sXDJBT0QgNQey6mwqLeU=
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
|
||||
@@ -832,6 +837,9 @@ google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMt
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
|
||||
Reference in New Issue
Block a user