mirror of
https://github.com/go-kratos/kratos.git
synced 2025-01-07 23:02:12 +02:00
add etcd naming
This commit is contained in:
parent
4d47b09111
commit
272f26a26b
2
go.mod
2
go.mod
@ -6,6 +6,7 @@ require (
|
||||
cloud.google.com/go v0.41.0 // indirect
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/aristanetworks/goarista v0.0.0-20190409234242-46f4bc7b73ef // indirect
|
||||
github.com/coreos/etcd v3.3.13+incompatible
|
||||
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d // indirect
|
||||
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect
|
||||
github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 // indirect
|
||||
@ -51,7 +52,6 @@ require (
|
||||
gopkg.in/go-playground/validator.v9 v9.26.0
|
||||
gopkg.in/yaml.v2 v2.2.2
|
||||
honnef.co/go/tools v0.0.0-20190605142022-0a11fc526260 // indirect
|
||||
|
||||
)
|
||||
|
||||
replace (
|
||||
|
12
go.sum
12
go.sum
@ -2,11 +2,16 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/aristanetworks/goarista v0.0.0-20190409234242-46f4bc7b73ef h1:ajsnF5qTstiBlP+V/mgh91zZfoKP477KfSmRoCoyYGU=
|
||||
github.com/aristanetworks/goarista v0.0.0-20190409234242-46f4bc7b73ef/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/etcd v3.3.13+incompatible h1:8F3hqu9fGYLBifCmRCJsicFqDx/D68Rt3q1JMazcgBQ=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d h1:SwD98825d6bdB+pEuTxWOXiSjBrHdOl/UVp75eI7JT8=
|
||||
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
|
||||
@ -23,10 +28,13 @@ github.com/dgryski/go-farm v0.0.0-20190323231341-8198c7b169ec/go.mod h1:SqUrOPUn
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/etcd-io/etcd v3.3.10+incompatible/go.mod h1:cdZ77EstHBwVtD6iTgzgvogwcjo9m4iOqoijouPJ4bs=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
||||
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
||||
github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
|
||||
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||
github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=
|
||||
@ -44,6 +52,7 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
|
||||
github.com/golang/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/net v0.0.0-20190311183353-d8887717615a h1:4V+LPwzBFLRg7XSXZw133Jsur1mTVMY73hIv/FTdrbg=
|
||||
github.com/golang/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
@ -75,9 +84,11 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
|
||||
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||
@ -134,6 +145,7 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
|
284
pkg/naming/etcd/etcd.go
Normal file
284
pkg/naming/etcd/etcd.go
Normal file
@ -0,0 +1,284 @@
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/bilibili/kratos/pkg/log"
|
||||
"github.com/bilibili/kratos/pkg/naming"
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
"github.com/coreos/etcd/mvcc/mvccpb"
|
||||
)
|
||||
const (
|
||||
Prefix = "kratos_etcd3"
|
||||
|
||||
RegisterTTL = 30
|
||||
)
|
||||
var (
|
||||
_once sync.Once
|
||||
_builder naming.Builder
|
||||
|
||||
ErrDuplication = errors.New("etcd: instance duplicate registration")
|
||||
)
|
||||
|
||||
// Builder return default etcd resolver builder.
|
||||
func Builder(c *clientv3.Config) naming.Builder {
|
||||
_once.Do(func() {
|
||||
_builder = New(c)
|
||||
})
|
||||
return _builder
|
||||
}
|
||||
// Build register resolver into default etcd.
|
||||
func Build(c *clientv3.Config,id string) naming.Resolver {
|
||||
return Builder(c).Build(id)
|
||||
}
|
||||
//Etcd is a etcd clientv3 builder
|
||||
type EtcdBuilder struct {
|
||||
cli *clientv3.Client
|
||||
ctx context.Context
|
||||
cancelFunc context.CancelFunc
|
||||
|
||||
mutex sync.RWMutex
|
||||
apps map[string]*appInfo
|
||||
registry map[string]struct{}
|
||||
}
|
||||
type appInfo struct {
|
||||
resolver map[*Resolve]struct{}
|
||||
ins atomic.Value
|
||||
e *EtcdBuilder
|
||||
once sync.Once
|
||||
}
|
||||
// Resolve etch resolver.
|
||||
type Resolve struct {
|
||||
id string
|
||||
event chan struct{}
|
||||
e *EtcdBuilder
|
||||
|
||||
}
|
||||
|
||||
func New(c *clientv3.Config) (e *EtcdBuilder){
|
||||
cli,err := clientv3.New(*c)
|
||||
if(err != nil){
|
||||
panic(err)
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
e = &EtcdBuilder{
|
||||
cli: cli,
|
||||
ctx: ctx,
|
||||
cancelFunc: cancel,
|
||||
apps: map[string]*appInfo{},
|
||||
registry: map[string]struct{}{},
|
||||
delete: make(chan *appInfo, 10),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Build disovery resovler builder.
|
||||
func (e *EtcdBuilder) Build(appid string) naming.Resolver {
|
||||
r := &Resolve{
|
||||
id: appid,
|
||||
e: e,
|
||||
event: make(chan struct{}, 1),
|
||||
}
|
||||
e.mutex.Lock()
|
||||
app, ok := e.apps[appid]
|
||||
if !ok {
|
||||
app = &appInfo{
|
||||
resolver: make(map[*Resolve]struct{}),
|
||||
e:e,
|
||||
}
|
||||
e.apps[appid] = app
|
||||
}
|
||||
app.resolver[r] = struct{}{}
|
||||
e.mutex.Unlock()
|
||||
if ok {
|
||||
select {
|
||||
case r.event <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
app.once.Do(func(){
|
||||
go app.watch(appid)
|
||||
log.Info("etcd: AddWatch(%s) already watch(%v)", appid, ok)
|
||||
})
|
||||
return r
|
||||
}
|
||||
|
||||
// Scheme return etcd's scheme
|
||||
func (e *EtcdBuilder) Scheme() string {
|
||||
return "etcd"
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
func (e *EtcdBuilder) Register(ctx context.Context, ins *naming.Instance) (cancelFunc context.CancelFunc, err error) {
|
||||
e.mutex.Lock()
|
||||
if _, ok := e.registry[ins.AppID]; ok {
|
||||
err = ErrDuplication
|
||||
} else {
|
||||
e.registry[ins.AppID] = struct{}{}
|
||||
}
|
||||
e.mutex.Unlock()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(e.ctx)
|
||||
if err = e.register(ctx, ins); err != nil {
|
||||
e.mutex.Lock()
|
||||
delete(e.registry, ins.AppID)
|
||||
e.mutex.Unlock()
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
ch := make(chan struct{}, 1)
|
||||
cancelFunc = context.CancelFunc(func() {
|
||||
cancel()
|
||||
<-ch
|
||||
})
|
||||
|
||||
go func() {
|
||||
//提前2秒续约 避免续约操作缓慢时租约过期
|
||||
ticker := time.NewTicker((RegisterTTL-2)*time.Second)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
_ = e.register(ctx, ins)
|
||||
case <-ctx.Done():
|
||||
_ = e.unregister(ins)
|
||||
ch <- struct{}{}
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
return
|
||||
}
|
||||
//注册和续约公用一个操作
|
||||
func (e *EtcdBuilder)register(ctx context.Context, ins *naming.Instance) (err error){
|
||||
prefix := e.getprefix(ins)
|
||||
val ,_ := json.Marshal(ins)
|
||||
|
||||
ttlResp, err := e.cli.Grant(context.TODO(), int64(RegisterTTL))
|
||||
if(err != nil){
|
||||
log.Error("etcd: register client.Grant(%v) error(%v)",RegisterTTL,err)
|
||||
return err
|
||||
}
|
||||
_,err = e.cli.Put(ctx,prefix,string(val),clientv3.WithLease(ttlResp.ID))
|
||||
if(err != nil){
|
||||
log.Error("etcd: register client.Put(%v) appid(%s) hostname(%s) error(%v)",
|
||||
prefix,ins.AppID,ins.Hostname, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (e *EtcdBuilder)unregister(ins *naming.Instance) (err error){
|
||||
prefix := e.getprefix(ins)
|
||||
|
||||
if _,err = e.cli.Delete(context.TODO(),prefix); err != nil{
|
||||
log.Error("etcd: unregister client.Delete(%v) appid(%s) hostname(%s) error(%v)",
|
||||
prefix, ins.AppID, ins.Hostname, err)
|
||||
}
|
||||
log.Info("etcd: unregister client.Delete(%v) appid(%s) hostname(%s) success",
|
||||
prefix, ins.AppID, ins.Hostname)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
func (e *EtcdBuilder)getprefix(ins *naming.Instance) string{
|
||||
return fmt.Sprintf("/%s/%s/%s", Prefix, ins.AppID,ins.Hostname)
|
||||
}
|
||||
// Close stop all running process including etcdfetch and register
|
||||
func (e *EtcdBuilder) Close() error {
|
||||
e.cancelFunc()
|
||||
return nil
|
||||
}
|
||||
func (a *appInfo)watch(appID string){
|
||||
_ = a.fetchstore(appID)
|
||||
prefix := fmt.Sprintf("/%s/%s/",Prefix,appID)
|
||||
rch := a.e.cli.Watch(a.e.ctx, prefix, clientv3.WithPrefix())
|
||||
for wresp := range rch {
|
||||
for _, ev := range wresp.Events {
|
||||
if(ev.Type == mvccpb.PUT || ev.Type == mvccpb.DELETE){
|
||||
_ = a.fetchstore(appID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (a *appInfo)fetchstore(appID string)(err error){
|
||||
prefix := fmt.Sprintf("/%s/%s/", Prefix, appID)
|
||||
resp ,err := a.e.cli.Get(a.e.ctx,prefix,clientv3.WithPrefix())
|
||||
if(err != nil){
|
||||
log.Error("etcd: fetch client.Get(%s) error(%+v)", prefix, err)
|
||||
return err
|
||||
}
|
||||
|
||||
ins,err := a.paserIns(resp)
|
||||
if(err != nil){
|
||||
return err
|
||||
}
|
||||
a.store(ins)
|
||||
return nil
|
||||
}
|
||||
func (a *appInfo)store(ins *naming.InstancesInfo){
|
||||
|
||||
a.ins.Store(ins)
|
||||
a.e.mutex.RLock()
|
||||
for rs := range a.resolver {
|
||||
select {
|
||||
case rs.event <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
a.e.mutex.RUnlock()
|
||||
}
|
||||
|
||||
|
||||
func (a *appInfo)paserIns(resp *clientv3.GetResponse)(ins *naming.InstancesInfo,err error){
|
||||
ins = &naming.InstancesInfo{
|
||||
Instances:make(map[string][]*naming.Instance,0),
|
||||
}
|
||||
for _, ev := range resp.Kvs {
|
||||
in := new(naming.Instance)
|
||||
|
||||
err := json.Unmarshal(ev.Value,in)
|
||||
if(err != nil){
|
||||
return nil,err
|
||||
}
|
||||
ins.Instances[in.Zone] = append(ins.Instances[in.Zone],in)
|
||||
}
|
||||
return ins,nil
|
||||
}
|
||||
// Watch watch instance.
|
||||
func (r *Resolve) Watch() <-chan struct{} {
|
||||
return r.event
|
||||
}
|
||||
|
||||
// Fetch fetch resolver instance.
|
||||
func (r *Resolve) Fetch(ctx context.Context) (ins *naming.InstancesInfo, ok bool) {
|
||||
r.e.mutex.RLock()
|
||||
app, ok := r.e.apps[r.id]
|
||||
r.e.mutex.RUnlock()
|
||||
if ok {
|
||||
ins, ok = app.ins.Load().(*naming.InstancesInfo)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Close close resolver.
|
||||
func (r *Resolve) Close() error {
|
||||
r.e.mutex.Lock()
|
||||
if app, ok := r.e.apps[r.id]; ok && len(app.resolver) != 0 {
|
||||
delete(app.resolver, r)
|
||||
}
|
||||
r.e.mutex.Unlock()
|
||||
return nil
|
||||
}
|
93
pkg/naming/etcd/etcd_test.go
Normal file
93
pkg/naming/etcd/etcd_test.go
Normal file
@ -0,0 +1,93 @@
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/bilibili/kratos/pkg/naming"
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
|
||||
config := &clientv3.Config{
|
||||
Endpoints:[]string{"127.0.0.1:2379",},
|
||||
}
|
||||
|
||||
builder := New(config)
|
||||
app1 := builder.Build("app1")
|
||||
|
||||
go func() {
|
||||
fmt.Printf("Watch \n")
|
||||
for{
|
||||
select{
|
||||
case <- app1.Watch():
|
||||
fmt.Printf("app1 节点发生变化 \n")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
app1Cancel,err := builder.Register(context.Background(),&naming.Instance{
|
||||
AppID:"app1",
|
||||
Hostname:"h1",
|
||||
Zone:"z1",
|
||||
})
|
||||
|
||||
app2Cancel,err := builder.Register(context.Background(),&naming.Instance{
|
||||
AppID:"app2",
|
||||
Hostname:"h5",
|
||||
Zone:"z3",
|
||||
})
|
||||
|
||||
if(err != nil){
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
app2 := builder.Build("app2")
|
||||
|
||||
go func(){
|
||||
fmt.Println("节点列表")
|
||||
for {
|
||||
fmt.Printf("app1: ")
|
||||
r1,_ := app1.Fetch(context.Background())
|
||||
if(r1 != nil){
|
||||
for z,ins := range r1.Instances{
|
||||
fmt.Printf("zone: %s :",z)
|
||||
for _,in := range ins{
|
||||
fmt.Printf("app: %s host %s \n",in.AppID,in.Hostname)
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Printf("app2: ")
|
||||
r2,_ := app2.Fetch(context.Background())
|
||||
if(r2 != nil){
|
||||
for z,ins := range r2.Instances{
|
||||
fmt.Printf("zone: %s :",z)
|
||||
for _,in := range ins{
|
||||
fmt.Printf("app: %s host %s \n",in.AppID,in.Hostname)
|
||||
}
|
||||
}
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}()
|
||||
|
||||
time.Sleep(time.Second*5)
|
||||
fmt.Println("取消app1")
|
||||
app1Cancel()
|
||||
|
||||
time.Sleep(time.Second*10)
|
||||
fmt.Println("取消app2")
|
||||
app2Cancel()
|
||||
|
||||
|
||||
|
||||
wait := make(chan int,0)
|
||||
wait <- 1
|
||||
}
|
Loading…
Reference in New Issue
Block a user