87 lines
2.0 KiB
Go
87 lines
2.0 KiB
Go
|
package zk
|
||
|
|
||
|
import (
|
||
|
"github.com/samuel/go-zookeeper/zk"
|
||
|
|
||
|
"github.com/go-kit/kit/endpoint"
|
||
|
"github.com/go-kit/kit/log"
|
||
|
"github.com/go-kit/kit/sd"
|
||
|
"github.com/go-kit/kit/sd/cache"
|
||
|
)
|
||
|
|
||
|
// Subscriber yield endpoints stored in a certain ZooKeeper path. Any kind of
|
||
|
// change in that path is watched and will update the Subscriber endpoints.
|
||
|
type Subscriber struct {
|
||
|
client Client
|
||
|
path string
|
||
|
cache *cache.Cache
|
||
|
logger log.Logger
|
||
|
quitc chan struct{}
|
||
|
}
|
||
|
|
||
|
var _ sd.Subscriber = &Subscriber{}
|
||
|
|
||
|
// NewSubscriber returns a ZooKeeper subscriber. ZooKeeper will start watching
|
||
|
// the given path for changes and update the Subscriber endpoints.
|
||
|
func NewSubscriber(c Client, path string, factory sd.Factory, logger log.Logger) (*Subscriber, error) {
|
||
|
s := &Subscriber{
|
||
|
client: c,
|
||
|
path: path,
|
||
|
cache: cache.New(factory, logger),
|
||
|
logger: logger,
|
||
|
quitc: make(chan struct{}),
|
||
|
}
|
||
|
|
||
|
err := s.client.CreateParentNodes(s.path)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
instances, eventc, err := s.client.GetEntries(s.path)
|
||
|
if err != nil {
|
||
|
logger.Log("path", s.path, "msg", "failed to retrieve entries", "err", err)
|
||
|
return nil, err
|
||
|
}
|
||
|
logger.Log("path", s.path, "instances", len(instances))
|
||
|
s.cache.Update(instances)
|
||
|
|
||
|
go s.loop(eventc)
|
||
|
|
||
|
return s, nil
|
||
|
}
|
||
|
|
||
|
func (s *Subscriber) loop(eventc <-chan zk.Event) {
|
||
|
var (
|
||
|
instances []string
|
||
|
err error
|
||
|
)
|
||
|
for {
|
||
|
select {
|
||
|
case <-eventc:
|
||
|
// We received a path update notification. Call GetEntries to
|
||
|
// retrieve child node data, and set a new watch, as ZK watches are
|
||
|
// one-time triggers.
|
||
|
instances, eventc, err = s.client.GetEntries(s.path)
|
||
|
if err != nil {
|
||
|
s.logger.Log("path", s.path, "msg", "failed to retrieve entries", "err", err)
|
||
|
continue
|
||
|
}
|
||
|
s.logger.Log("path", s.path, "instances", len(instances))
|
||
|
s.cache.Update(instances)
|
||
|
|
||
|
case <-s.quitc:
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Endpoints implements the Subscriber interface.
|
||
|
func (s *Subscriber) Endpoints() ([]endpoint.Endpoint, error) {
|
||
|
return s.cache.Endpoints(), nil
|
||
|
}
|
||
|
|
||
|
// Stop terminates the Subscriber.
|
||
|
func (s *Subscriber) Stop() {
|
||
|
close(s.quitc)
|
||
|
}
|