13 changed files with 178 additions and 11 deletions
@ -0,0 +1,112 @@
|
||||
package consul |
||||
|
||||
import ( |
||||
"math" |
||||
"sig-pub/pkg/utils/collect" |
||||
"sig-pub/pkg/utils/retry" |
||||
"sig-pub/pkg/zlog" |
||||
"time" |
||||
|
||||
"github.com/hashicorp/consul/api" |
||||
"github.com/hashicorp/consul/api/watch" |
||||
) |
||||
|
||||
// 定义watcher
|
||||
type Watcher struct { |
||||
client *api.Client |
||||
wp *watch.Plan // 总的Services变化对应的Plan
|
||||
watchers *collect.SyncMap[string, *watch.Plan] // 对已经进行监控的service作个记录
|
||||
handler func(serviceName string, passing bool) |
||||
} |
||||
|
||||
func NewWatcher(client *api.Client, handler func(serviceName string, passing bool)) *Watcher { |
||||
return &Watcher{ |
||||
client: client, |
||||
watchers: collect.NewSyncMap[string, *watch.Plan](), |
||||
handler: handler, |
||||
} |
||||
} |
||||
|
||||
// WatchServices
|
||||
// watch services doc: https://www.consul.io/docs/dynamic-app-config/watches#services
|
||||
func (w *Watcher) WatchServices() (err error) { |
||||
w.wp, err = watch.Parse(map[string]any{ |
||||
"type": "services", |
||||
}) |
||||
if err != nil { |
||||
return |
||||
} |
||||
w.wp.Handler = func(i uint64, data any) { |
||||
switch d := data.(type) { |
||||
// services
|
||||
case map[string][]string: |
||||
services := make([]string, 0, len(d)) |
||||
for i := range d { |
||||
if i == "consul" { |
||||
continue |
||||
} |
||||
services = append(services, i) |
||||
if _, loaded := w.watchers.LoadOrStore(i, nil); !loaded { |
||||
w.registerServiceWatcher(i) |
||||
} |
||||
} |
||||
zlog.Infof("consul services update: %v", services) |
||||
|
||||
// remove unknown services from watchers
|
||||
// var dels []string
|
||||
// w.watchers.Range(func(k string, wp *watch.Plan) bool {
|
||||
// wp.Stop()
|
||||
// dels = append(dels, k)
|
||||
// return true
|
||||
// })
|
||||
// for _, svc := range dels {
|
||||
// w.watchers.Delete(svc)
|
||||
// }
|
||||
default: |
||||
zlog.Debugf("unknown consul watch type: %#v", &d) |
||||
} |
||||
} |
||||
|
||||
go func() { |
||||
if err := w.wp.RunWithClientAndHclog(w.client, nil); err != nil { |
||||
zlog.Error("watch services error: ", err) |
||||
retry.DoWithFixDelay(math.MaxUint32, 3*time.Second, func(retryTimes uint32) (_ struct{}, err error) { |
||||
err = w.WatchServices() |
||||
return |
||||
}) |
||||
} |
||||
}() |
||||
return |
||||
} |
||||
|
||||
// 将consul新增的service加入,并监控
|
||||
// doc: https://www.consul.io/docs/dynamic-app-config/watches#service
|
||||
func (w *Watcher) registerServiceWatcher(serviceName string) error { |
||||
wp, err := watch.Parse(map[string]any{ |
||||
"type": "service", |
||||
"service": serviceName, |
||||
}) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
// 定义service变化后所执行的程序(函数)handler
|
||||
wp.Handler = func(idx uint64, data any) { |
||||
switch d := data.(type) { |
||||
case []*api.ServiceEntry: |
||||
for _, i := range d { |
||||
if w.handler != nil { |
||||
w.handler(i.Service.Service, i.Checks.AggregatedStatus() == "passing") // status: passing / critical
|
||||
} |
||||
// fmt.Printf("service %s 已变化", i.Service.Service)
|
||||
// // 打印service的状态
|
||||
// fmt.Println("service status: ", i.Checks.AggregatedStatus())
|
||||
} |
||||
} |
||||
} |
||||
// 启动监控
|
||||
go wp.RunWithClientAndHclog(w.client, nil) |
||||
|
||||
w.watchers.Store(serviceName, wp) |
||||
return nil |
||||
} |
||||
Loading…
Reference in new issue