mirror of
https://github.com/go-micro/go-micro.git
synced 2024-12-12 08:23:58 +02:00
143 lines
2.6 KiB
Go
143 lines
2.6 KiB
Go
|
package eureka
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"time"
|
||
|
|
||
|
"github.com/hudl/fargo"
|
||
|
"github.com/micro/go-micro/v2/registry"
|
||
|
)
|
||
|
|
||
|
type eurekaWatcher struct {
|
||
|
conn fargoConnection
|
||
|
exit chan bool
|
||
|
results chan *registry.Result
|
||
|
}
|
||
|
|
||
|
func newWatcher(conn fargoConnection, opts ...registry.WatchOption) registry.Watcher {
|
||
|
var wo registry.WatchOptions
|
||
|
for _, o := range opts {
|
||
|
o(&wo)
|
||
|
}
|
||
|
|
||
|
w := &eurekaWatcher{
|
||
|
conn: conn,
|
||
|
exit: make(chan bool),
|
||
|
results: make(chan *registry.Result),
|
||
|
}
|
||
|
|
||
|
// watch a single service
|
||
|
if len(wo.Service) > 0 {
|
||
|
done := make(chan struct{})
|
||
|
ch := conn.ScheduleAppUpdates(wo.Service, false, done)
|
||
|
go w.watch(ch, done)
|
||
|
go func() {
|
||
|
<-w.exit
|
||
|
close(done)
|
||
|
}()
|
||
|
return w
|
||
|
}
|
||
|
|
||
|
// watch all services
|
||
|
go w.poll()
|
||
|
return w
|
||
|
}
|
||
|
|
||
|
func (e *eurekaWatcher) poll() {
|
||
|
// list service ticker
|
||
|
t := time.NewTicker(time.Second * 10)
|
||
|
|
||
|
done := make(chan struct{})
|
||
|
services := make(map[string]<-chan fargo.AppUpdate)
|
||
|
|
||
|
for {
|
||
|
select {
|
||
|
case <-e.exit:
|
||
|
close(done)
|
||
|
return
|
||
|
case <-t.C:
|
||
|
apps, err := e.conn.GetApps()
|
||
|
if err != nil {
|
||
|
continue
|
||
|
}
|
||
|
for _, app := range apps {
|
||
|
if _, ok := services[app.Name]; ok {
|
||
|
continue
|
||
|
}
|
||
|
ch := e.conn.ScheduleAppUpdates(app.Name, false, done)
|
||
|
services[app.Name] = ch
|
||
|
go e.watch(ch, done)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *eurekaWatcher) watch(ch <-chan fargo.AppUpdate, done chan struct{}) {
|
||
|
for {
|
||
|
select {
|
||
|
// exit on exit
|
||
|
case <-e.exit:
|
||
|
return
|
||
|
// exit on done
|
||
|
case <-done:
|
||
|
return
|
||
|
// process updates
|
||
|
case u := <-ch:
|
||
|
if u.Err != nil {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// process instances independently
|
||
|
for _, instance := range u.App.Instances {
|
||
|
var action string
|
||
|
|
||
|
switch instance.Status {
|
||
|
// update
|
||
|
case fargo.UP:
|
||
|
action = "update"
|
||
|
// delete
|
||
|
case fargo.OUTOFSERVICE, fargo.UNKNOWN, fargo.DOWN:
|
||
|
action = "delete"
|
||
|
// skip
|
||
|
default:
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// construct the service with a single node
|
||
|
service := appToService(&fargo.Application{
|
||
|
Name: u.App.Name,
|
||
|
Instances: []*fargo.Instance{instance},
|
||
|
})
|
||
|
|
||
|
if len(service) == 0 {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// in case we get bounced during processing
|
||
|
// check exit channels
|
||
|
select {
|
||
|
// send the update
|
||
|
case e.results <- ®istry.Result{Action: action, Service: service[0]}:
|
||
|
case <-done:
|
||
|
return
|
||
|
case <-e.exit:
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *eurekaWatcher) Next() (*registry.Result, error) {
|
||
|
select {
|
||
|
case <-e.exit:
|
||
|
return nil, errors.New("watcher stopped")
|
||
|
case r := <-e.results:
|
||
|
return r, nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *eurekaWatcher) Stop() {
|
||
|
close(e.exit)
|
||
|
}
|