1
0
mirror of https://github.com/go-micro/go-micro.git synced 2024-12-24 10:07:04 +02:00

Add remote lookup via router selector

This commit is contained in:
Asim Aslam 2019-06-26 19:27:38 +01:00
parent 76011b151d
commit cedcef032d

View File

@ -4,12 +4,15 @@ package router
import ( import (
"context" "context"
"net" "net"
"os"
"sort" "sort"
"strconv" "strconv"
"sync" "sync"
"github.com/micro/go-micro/client"
"github.com/micro/go-micro/client/selector" "github.com/micro/go-micro/client/selector"
"github.com/micro/go-micro/network/router" "github.com/micro/go-micro/network/router"
pb "github.com/micro/go-micro/network/router/proto"
"github.com/micro/go-micro/registry" "github.com/micro/go-micro/registry"
) )
@ -18,10 +21,64 @@ type routerSelector struct {
// the router // the router
r router.Router r router.Router
// the client for the remote router
c pb.RouterService
// address of the remote router
addr string
// whether to use the remote router
remote bool
} }
type clientKey struct{}
type routerKey struct{} type routerKey struct{}
// getRoutes returns the routes whether they are remote or local
func (r *routerSelector) getRoutes(service string) ([]router.Route, error) {
if !r.remote {
// lookup router for routes for the service
return r.r.Table().Lookup(router.NewQuery(
router.QueryDestination(service),
))
}
// lookup the remote router
var clientOpts []client.CallOption
// set the remote address if specified
if len(r.addr) > 0 {
clientOpts = append(clientOpts, client.WithAddress(r.addr))
}
// call the router
pbRoutes, err := r.c.Lookup(context.Background(), &pb.LookupRequest{
Query: &pb.Query{
Destination: service,
},
}, clientOpts...)
if err != nil {
return nil, err
}
var routes []router.Route
// convert from pb to []*router.Route
for _, r := range pbRoutes.Routes {
routes = append(routes, router.Route{
Destination: r.Destination,
Gateway: r.Gateway,
Router: r.Router,
Network: r.Network,
Metric: int(r.Metric),
})
}
return routes, nil
}
func (r *routerSelector) Init(opts ...selector.Option) error { func (r *routerSelector) Init(opts ...selector.Option) error {
// no op // no op
return nil return nil
@ -32,11 +89,8 @@ func (r *routerSelector) Options() selector.Options {
} }
func (r *routerSelector) Select(service string, opts ...selector.SelectOption) (selector.Next, error) { func (r *routerSelector) Select(service string, opts ...selector.SelectOption) (selector.Next, error) {
// lookup router for routes for the service // TODO: pull routes asynchronously and cache
routes, err := r.r.Table().Lookup(router.NewQuery( routes, err := r.getRoutes(service)
router.QueryDestination(service),
))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -124,7 +178,7 @@ func NewSelector(opts ...selector.Option) selector.Selector {
options.Registry = registry.DefaultRegistry options.Registry = registry.DefaultRegistry
} }
// try get from the context // try get router from the context
r, ok := options.Context.Value(routerKey{}).(router.Router) r, ok := options.Context.Value(routerKey{}).(router.Router)
if !ok { if !ok {
// TODO: Use router.DefaultRouter? // TODO: Use router.DefaultRouter?
@ -133,12 +187,43 @@ func NewSelector(opts ...selector.Option) selector.Selector {
) )
} }
// start the router advertisements // try get client from the context
r.Advertise() c, ok := options.Context.Value(clientKey{}).(client.Client)
if !ok {
c = client.DefaultClient
}
// get the router from env vars if its a remote service
remote := true
routerName := os.Getenv("MICRO_ROUTER")
routerAddress := os.Getenv("MICRO_ROUTER_ADDRESS")
// start the router advertisements if we're running it locally
if len(routerName) == 0 && len(routerAddress) == 0 {
go r.Advertise()
remote = false
}
return &routerSelector{ return &routerSelector{
opts: options, opts: options,
// set the internal router
r: r, r: r,
// set the client
c: pb.NewRouterService(routerName, c),
// address of router
addr: routerAddress,
// let ourselves know to use the remote router
remote: remote,
}
}
// WithClient sets the client for the request
func WithClient(c client.Client) selector.Option {
return func(o *selector.Options) {
if o.Context == nil {
o.Context = context.Background()
}
o.Context = context.WithValue(o.Context, clientKey{}, c)
} }
} }