router/registry: add fallback if routes aren't found in the cache (#1758)

* router/registry: add fallback if routes aren't found in the cache

* router: fix rlock bug

* router/registry: pass fetchRoutes into the table, not the router
This commit is contained in:
ben-toogood 2020-06-30 09:53:49 +01:00 committed by GitHub
parent df3e5364ca
commit deea8fecf4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 51 additions and 8 deletions

View File

@ -48,10 +48,13 @@ func newRouter(opts ...Option) Router {
// construct the router
r := &router{
options: options,
table: newTable(),
subscribers: make(map[string]chan *Advert),
}
// create the new table, passing the fetchRoute method in as a fallback if
// the table doesn't contain the result for a query.
r.table = newTable(r.fetchRoutes)
// start the router and return
r.start()
return r
@ -176,6 +179,29 @@ func (r *router) manageRegistryRoutes(reg registry.Registry, action string) erro
return nil
}
// fetchRoutes retrieves all the routes for a given service and creates them in the routing table
func (r *router) fetchRoutes(service string) error {
services, err := r.options.Registry.GetService(service, registry.GetDomain(registry.WildcardDomain))
if err != nil {
return fmt.Errorf("failed getting services: %v", err)
}
for _, srv := range services {
var domain string
if srv.Metadata != nil && len(srv.Metadata["domain"]) > 0 {
domain = srv.Metadata["domain"]
} else {
domain = registry.WildcardDomain
}
if err := r.manageRoutes(srv, "create", domain); err != nil {
return err
}
}
return nil
}
// watchRegistry watches registry and updates routing table based on the received events.
// It returns error if either the registry watcher fails with error or if the routing table update fails.
func (r *router) watchRegistry(w registry.Watcher) error {

View File

@ -19,6 +19,8 @@ var (
// table is an in-memory routing table
type table struct {
sync.RWMutex
// fetchRoutes for a service
fetchRoutes func(string) error
// routes stores service routes
routes map[string]map[uint64]Route
// watchers stores table watchers
@ -26,10 +28,11 @@ type table struct {
}
// newtable creates a new routing table and returns it
func newTable(opts ...Option) *table {
func newTable(fetchRoutes func(string) error, opts ...Option) *table {
return &table{
routes: make(map[string]map[uint64]Route),
watchers: make(map[string]*tableWatcher),
fetchRoutes: fetchRoutes,
routes: make(map[string]map[uint64]Route),
watchers: make(map[string]*tableWatcher),
}
}
@ -249,10 +252,23 @@ func (t *table) Query(q ...QueryOption) ([]Route, error) {
}
if opts.Service != "*" {
if _, ok := t.routes[opts.Service]; !ok {
return nil, ErrRouteNotFound
// try and load services from the cache
if _, ok := t.routes[opts.Service]; ok {
return findRoutes(t.routes[opts.Service], opts.Address, opts.Gateway, opts.Network, opts.Router, opts.Strategy), nil
}
return findRoutes(t.routes[opts.Service], opts.Address, opts.Gateway, opts.Network, opts.Router, opts.Strategy), nil
// load the cache and try again
t.RUnlock()
if err := t.fetchRoutes(opts.Service); err != nil {
return nil, err
}
t.RLock()
if _, ok := t.routes[opts.Service]; ok {
return findRoutes(t.routes[opts.Service], opts.Address, opts.Gateway, opts.Network, opts.Router, opts.Strategy), nil
}
return nil, ErrRouteNotFound
}
// search through all destinations

View File

@ -6,7 +6,8 @@ import (
)
func testSetup() (*table, Route) {
table := newTable()
router := newRouter().(*router)
table := router.table
route := Route{
Service: "dest.svc",