Remove go routines for mdns watcher and cache registry (#919)
This commit is contained in:
parent
b84134581c
commit
254045e9f3
44
registry/cache/cache.go
vendored
44
registry/cache/cache.go
vendored
@ -39,6 +39,8 @@ type cache struct {
|
|||||||
// used to stop the cache
|
// used to stop the cache
|
||||||
exit chan bool
|
exit chan bool
|
||||||
|
|
||||||
|
// indicate whether its running
|
||||||
|
running bool
|
||||||
// status of the registry
|
// status of the registry
|
||||||
// used to hold onto the cache
|
// used to hold onto the cache
|
||||||
// in failure state
|
// in failure state
|
||||||
@ -157,13 +159,26 @@ func (c *cache) get(service string) ([]*registry.Service, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// watch service if not watched
|
// watch service if not watched
|
||||||
if _, ok := c.watched[service]; !ok {
|
_, ok := c.watched[service]
|
||||||
go c.run(service)
|
|
||||||
}
|
|
||||||
|
|
||||||
// unlock the read lock
|
// unlock the read lock
|
||||||
c.RUnlock()
|
c.RUnlock()
|
||||||
|
|
||||||
|
// check if its being watched
|
||||||
|
if !ok {
|
||||||
|
c.Lock()
|
||||||
|
|
||||||
|
// set to watched
|
||||||
|
c.watched[service] = true
|
||||||
|
|
||||||
|
// only kick it off if not running
|
||||||
|
if !c.running {
|
||||||
|
go c.run()
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
// get and return services
|
// get and return services
|
||||||
return get(service, cp)
|
return get(service, cp)
|
||||||
}
|
}
|
||||||
@ -181,6 +196,11 @@ func (c *cache) update(res *registry.Result) {
|
|||||||
c.Lock()
|
c.Lock()
|
||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
|
|
||||||
|
// only save watched services
|
||||||
|
if _, ok := c.watched[res.Service.Name]; !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
services, ok := c.cache[res.Service.Name]
|
services, ok := c.cache[res.Service.Name]
|
||||||
if !ok {
|
if !ok {
|
||||||
// we're not going to cache anything
|
// we're not going to cache anything
|
||||||
@ -283,16 +303,16 @@ func (c *cache) update(res *registry.Result) {
|
|||||||
|
|
||||||
// run starts the cache watcher loop
|
// run starts the cache watcher loop
|
||||||
// it creates a new watcher if there's a problem
|
// it creates a new watcher if there's a problem
|
||||||
func (c *cache) run(service string) {
|
func (c *cache) run() {
|
||||||
// set watcher
|
|
||||||
c.Lock()
|
c.Lock()
|
||||||
c.watched[service] = true
|
c.running = true
|
||||||
c.Unlock()
|
c.Unlock()
|
||||||
|
|
||||||
// delete watcher on exit
|
// reset watcher on exit
|
||||||
defer func() {
|
defer func() {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
delete(c.watched, service)
|
c.watched = make(map[string]bool)
|
||||||
|
c.running = false
|
||||||
c.Unlock()
|
c.Unlock()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -309,10 +329,7 @@ func (c *cache) run(service string) {
|
|||||||
time.Sleep(time.Duration(j) * time.Millisecond)
|
time.Sleep(time.Duration(j) * time.Millisecond)
|
||||||
|
|
||||||
// create new watcher
|
// create new watcher
|
||||||
w, err := c.Registry.Watch(
|
w, err := c.Registry.Watch()
|
||||||
registry.WatchService(service),
|
|
||||||
)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if c.quit() {
|
if c.quit() {
|
||||||
return
|
return
|
||||||
@ -414,6 +431,9 @@ func (c *cache) GetService(service string) ([]*registry.Service, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *cache) Stop() {
|
func (c *cache) Stop() {
|
||||||
|
c.Lock()
|
||||||
|
defer c.Unlock()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-c.exit:
|
case <-c.exit:
|
||||||
return
|
return
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/micro/mdns"
|
"github.com/micro/mdns"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -37,6 +38,14 @@ type mdnsRegistry struct {
|
|||||||
|
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
services map[string][]*mdnsEntry
|
services map[string][]*mdnsEntry
|
||||||
|
|
||||||
|
mtx sync.RWMutex
|
||||||
|
|
||||||
|
// watchers
|
||||||
|
watchers map[string]*mdnsWatcher
|
||||||
|
|
||||||
|
// listener
|
||||||
|
listener chan *mdns.ServiceEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRegistry(opts ...Option) Registry {
|
func newRegistry(opts ...Option) Registry {
|
||||||
@ -61,6 +70,7 @@ func newRegistry(opts ...Option) Registry {
|
|||||||
opts: options,
|
opts: options,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
services: make(map[string][]*mdnsEntry),
|
services: make(map[string][]*mdnsEntry),
|
||||||
|
watchers: make(map[string]*mdnsWatcher),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,15 +356,88 @@ func (m *mdnsRegistry) Watch(opts ...WatchOption) (Watcher, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
md := &mdnsWatcher{
|
md := &mdnsWatcher{
|
||||||
wo: wo,
|
id: uuid.New().String(),
|
||||||
ch: make(chan *mdns.ServiceEntry, 32),
|
wo: wo,
|
||||||
exit: make(chan struct{}),
|
ch: make(chan *mdns.ServiceEntry, 32),
|
||||||
domain: m.domain,
|
exit: make(chan struct{}),
|
||||||
|
domain: m.domain,
|
||||||
|
registry: m,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.mtx.Lock()
|
||||||
|
defer m.mtx.Unlock()
|
||||||
|
|
||||||
|
// save the watcher
|
||||||
|
m.watchers[md.id] = md
|
||||||
|
|
||||||
|
// check of the listener exists
|
||||||
|
if m.listener != nil {
|
||||||
|
return md, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// start the listener
|
||||||
go func() {
|
go func() {
|
||||||
if err := mdns.Listen(md.ch, md.exit); err != nil {
|
// go to infinity
|
||||||
md.Stop()
|
for {
|
||||||
|
m.mtx.Lock()
|
||||||
|
|
||||||
|
// just return if there are no watchers
|
||||||
|
if len(m.watchers) == 0 {
|
||||||
|
m.listener = nil
|
||||||
|
m.mtx.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// check existing listener
|
||||||
|
if m.listener != nil {
|
||||||
|
m.mtx.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset the listener
|
||||||
|
exit := make(chan struct{})
|
||||||
|
ch := make(chan *mdns.ServiceEntry, 32)
|
||||||
|
m.listener = ch
|
||||||
|
|
||||||
|
m.mtx.Unlock()
|
||||||
|
|
||||||
|
// send messages to the watchers
|
||||||
|
go func() {
|
||||||
|
send := func(w *mdnsWatcher, e *mdns.ServiceEntry) {
|
||||||
|
select {
|
||||||
|
case w.ch <- e:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-exit:
|
||||||
|
return
|
||||||
|
case e, ok := <-ch:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.mtx.RLock()
|
||||||
|
// send service entry to all watchers
|
||||||
|
for _, w := range m.watchers {
|
||||||
|
send(w, e)
|
||||||
|
}
|
||||||
|
m.mtx.RUnlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}()
|
||||||
|
|
||||||
|
// start listening, blocking call
|
||||||
|
mdns.Listen(ch, exit)
|
||||||
|
|
||||||
|
// mdns.Listen has unblocked
|
||||||
|
// kill the saved listener
|
||||||
|
m.mtx.Lock()
|
||||||
|
m.listener = nil
|
||||||
|
close(ch)
|
||||||
|
m.mtx.Unlock()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -8,11 +8,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type mdnsWatcher struct {
|
type mdnsWatcher struct {
|
||||||
|
id string
|
||||||
wo WatchOptions
|
wo WatchOptions
|
||||||
ch chan *mdns.ServiceEntry
|
ch chan *mdns.ServiceEntry
|
||||||
exit chan struct{}
|
exit chan struct{}
|
||||||
// the mdns domain
|
// the mdns domain
|
||||||
domain string
|
domain string
|
||||||
|
// the registry
|
||||||
|
registry *mdnsRegistry
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mdnsWatcher) Next() (*Result, error) {
|
func (m *mdnsWatcher) Next() (*Result, error) {
|
||||||
@ -76,5 +79,9 @@ func (m *mdnsWatcher) Stop() {
|
|||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
close(m.exit)
|
close(m.exit)
|
||||||
|
// remove self from the registry
|
||||||
|
m.registry.mtx.Lock()
|
||||||
|
delete(m.registry.watchers, m.id)
|
||||||
|
m.registry.mtx.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user