You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
2.7 KiB
Go
144 lines
2.7 KiB
Go
4 years ago
|
package discov
|
||
|
|
||
|
import (
|
||
|
"zero/core/discov/internal"
|
||
|
"zero/core/lang"
|
||
|
"zero/core/logx"
|
||
|
"zero/core/proc"
|
||
|
"zero/core/syncx"
|
||
|
"zero/core/threading"
|
||
|
|
||
|
"go.etcd.io/etcd/clientv3"
|
||
|
)
|
||
|
|
||
|
type (
|
||
|
PublisherOption func(client *Publisher)
|
||
|
|
||
|
Publisher struct {
|
||
|
endpoints []string
|
||
|
key string
|
||
|
fullKey string
|
||
|
id int64
|
||
|
value string
|
||
|
lease clientv3.LeaseID
|
||
|
quit *syncx.DoneChan
|
||
|
pauseChan chan lang.PlaceholderType
|
||
|
resumeChan chan lang.PlaceholderType
|
||
|
}
|
||
|
)
|
||
|
|
||
|
func NewPublisher(endpoints []string, key, value string, opts ...PublisherOption) *Publisher {
|
||
|
publisher := &Publisher{
|
||
|
endpoints: endpoints,
|
||
|
key: key,
|
||
|
value: value,
|
||
|
quit: syncx.NewDoneChan(),
|
||
|
pauseChan: make(chan lang.PlaceholderType),
|
||
|
resumeChan: make(chan lang.PlaceholderType),
|
||
|
}
|
||
|
|
||
|
for _, opt := range opts {
|
||
|
opt(publisher)
|
||
|
}
|
||
|
|
||
|
return publisher
|
||
|
}
|
||
|
|
||
|
func (p *Publisher) KeepAlive() error {
|
||
|
cli, err := internal.GetRegistry().GetConn(p.endpoints)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
p.lease, err = p.register(cli)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
proc.AddWrapUpListener(func() {
|
||
|
p.Stop()
|
||
|
})
|
||
|
|
||
|
return p.keepAliveAsync(cli)
|
||
|
}
|
||
|
|
||
|
func (p *Publisher) Pause() {
|
||
|
p.pauseChan <- lang.Placeholder
|
||
|
}
|
||
|
|
||
|
func (p *Publisher) Resume() {
|
||
|
p.resumeChan <- lang.Placeholder
|
||
|
}
|
||
|
|
||
|
func (p *Publisher) Stop() {
|
||
|
p.quit.Close()
|
||
|
}
|
||
|
|
||
|
func (p *Publisher) keepAliveAsync(cli internal.EtcdClient) error {
|
||
|
ch, err := cli.KeepAlive(cli.Ctx(), p.lease)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
threading.GoSafe(func() {
|
||
|
for {
|
||
|
select {
|
||
|
case _, ok := <-ch:
|
||
|
if !ok {
|
||
|
p.revoke(cli)
|
||
|
if err := p.KeepAlive(); err != nil {
|
||
|
logx.Errorf("KeepAlive: %s", err.Error())
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
case <-p.pauseChan:
|
||
|
logx.Infof("paused etcd renew, key: %s, value: %s", p.key, p.value)
|
||
|
p.revoke(cli)
|
||
|
select {
|
||
|
case <-p.resumeChan:
|
||
|
if err := p.KeepAlive(); err != nil {
|
||
|
logx.Errorf("KeepAlive: %s", err.Error())
|
||
|
}
|
||
|
return
|
||
|
case <-p.quit.Done():
|
||
|
return
|
||
|
}
|
||
|
case <-p.quit.Done():
|
||
|
p.revoke(cli)
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (p *Publisher) register(client internal.EtcdClient) (clientv3.LeaseID, error) {
|
||
|
resp, err := client.Grant(client.Ctx(), TimeToLive)
|
||
|
if err != nil {
|
||
|
return clientv3.NoLease, err
|
||
|
}
|
||
|
|
||
|
lease := resp.ID
|
||
|
if p.id > 0 {
|
||
|
p.fullKey = makeEtcdKey(p.key, p.id)
|
||
|
} else {
|
||
|
p.fullKey = makeEtcdKey(p.key, int64(lease))
|
||
|
}
|
||
|
_, err = client.Put(client.Ctx(), p.fullKey, p.value, clientv3.WithLease(lease))
|
||
|
|
||
|
return lease, err
|
||
|
}
|
||
|
|
||
|
func (p *Publisher) revoke(cli internal.EtcdClient) {
|
||
|
if _, err := cli.Revoke(cli.Ctx(), p.lease); err != nil {
|
||
|
logx.Error(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func WithId(id int64) PublisherOption {
|
||
|
return func(publisher *Publisher) {
|
||
|
publisher.id = id
|
||
|
}
|
||
|
}
|