mucp Proxy no longer uses RPC interface of router.Router directly

This commit is contained in:
Milos Gajdos 2019-07-24 18:13:51 +01:00
parent 388ac34b7c
commit b55adc0c30
No known key found for this signature in database
GPG Key ID: 8B31058CC55DFD4F

View File

@ -4,12 +4,10 @@ package mucp
import ( import (
"context" "context"
"io" "io"
"os"
"strings" "strings"
"sync" "sync"
"github.com/micro/go-micro/client" "github.com/micro/go-micro/client"
"github.com/micro/go-micro/client/selector"
"github.com/micro/go-micro/codec" "github.com/micro/go-micro/codec"
"github.com/micro/go-micro/codec/bytes" "github.com/micro/go-micro/codec/bytes"
"github.com/micro/go-micro/config/options" "github.com/micro/go-micro/config/options"
@ -17,7 +15,6 @@ import (
"github.com/micro/go-micro/network/router" "github.com/micro/go-micro/network/router"
"github.com/micro/go-micro/server" "github.com/micro/go-micro/server"
pb "github.com/micro/go-micro/network/router/proto"
"github.com/micro/go-micro/network/router/table" "github.com/micro/go-micro/network/router/table"
) )
@ -27,7 +24,7 @@ type Proxy struct {
// embed options // embed options
options.Options options.Options
// Endpoint specified the fixed service endpoint to call. // Endpoint specifies the fixed service endpoint to call.
Endpoint string Endpoint string
// The client to use for outbound requests // The client to use for outbound requests
@ -36,12 +33,9 @@ type Proxy struct {
// The router for routes // The router for routes
Router router.Router Router router.Router
// The router service client
RouterService pb.RouterService
// A fib of routes service:address // A fib of routes service:address
sync.RWMutex sync.RWMutex
Routes map[string][]table.Route Routes map[string]map[uint64]table.Route
} }
// read client request and write to server // read client request and write to server
@ -79,9 +73,8 @@ func readLoop(r server.Request, s client.Stream) error {
} }
} }
func (p *Proxy) getRoute(service string) ([]string, error) { // toNodes returns a list of node addresses from given routes
// converts routes to just addresses func toNodes(routes map[uint64]table.Route) []string {
toNodes := func(routes []table.Route) []string {
var nodes []string var nodes []string
for _, node := range routes { for _, node := range routes {
address := node.Address address := node.Address
@ -93,141 +86,41 @@ func (p *Proxy) getRoute(service string) ([]string, error) {
return nodes return nodes
} }
func (p *Proxy) getRoute(service string) ([]string, error) {
// lookup the route cache first // lookup the route cache first
p.RLock() p.Lock()
routes, ok := p.Routes[service] routes, ok := p.Routes[service]
// got it!
if ok { if ok {
p.RUnlock() p.Unlock()
return toNodes(routes), nil return toNodes(routes), nil
} }
p.RUnlock() p.Routes[service] = make(map[uint64]table.Route)
// route cache miss, now lookup the router
// if it does not exist, don't error out
// the proxy will just hand off to the client
// and try the registry
// in future we might set a default gateway
if p.Router != nil {
// lookup the router
routes, err := p.Router.Lookup(
table.NewQuery(table.QueryService(service)),
)
if err != nil {
return nil, err
}
p.Lock()
if p.Routes == nil {
p.Routes = make(map[string][]table.Route)
}
p.Routes[service] = routes
p.Unlock() p.Unlock()
return toNodes(routes), nil // if the router is broken return error
if status := p.Router.Status(); status.Code == router.Error {
return nil, status.Error
} }
// we've tried getting cached routes // lookup the routes in the router
// we've tried using the router results, err := p.Router.Lookup(table.NewQuery(table.QueryService(service)))
addr := os.Getenv("MICRO_ROUTER_ADDRESS")
name := os.Getenv("MICRO_ROUTER")
// no router is specified we're going to set the default
if len(name) == 0 && len(addr) == 0 {
p.Router = router.DefaultRouter
go p.Router.Advertise()
// recursively execute getRoute
return p.getRoute(service)
}
if len(name) == 0 {
name = "go.micro.router"
}
// lookup the remote router
var addrs []string
// set the remote address if specified
if len(addr) > 0 {
addrs = append(addrs, addr)
} else {
// we have a name so we need to check the registry
services, err := p.Client.Options().Registry.GetService(name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, service := range services { // update the proxy cache
for _, node := range service.Nodes { p.Lock()
addrs = append(addrs, node.Address) for _, route := range results {
} p.Routes[service][route.Hash()] = route
}
}
// no router addresses available
if len(addrs) == 0 {
return nil, selector.ErrNoneAvailable
}
var pbRoutes *pb.LookupResponse
var gerr error
// set default client
if p.RouterService == nil {
p.RouterService = pb.NewRouterService(name, p.Client)
}
// TODO: implement backoff and retries
for _, addr := range addrs {
// call the router
proutes, err := p.RouterService.Lookup(context.Background(), &pb.LookupRequest{
Query: &pb.Query{
Service: service,
},
}, client.WithAddress(addr))
if err != nil {
gerr = err
continue
}
// set routes
pbRoutes = proutes
break
}
// errored out
if gerr != nil {
return nil, gerr
}
// no routes
if pbRoutes == nil {
return nil, selector.ErrNoneAvailable
}
// convert from pb to []*router.Route
for _, r := range pbRoutes.Routes {
routes = append(routes, table.Route{
Service: r.Service,
Address: r.Address,
Gateway: r.Gateway,
Network: r.Network,
Link: r.Link,
Metric: int(r.Metric),
})
} }
routes = p.Routes[service]
p.Unlock()
return toNodes(routes), nil return toNodes(routes), nil
} }
// ServeRequest honours the server.Router interface // ServeRequest honours the server.Router interface
func (p *Proxy) ServeRequest(ctx context.Context, req server.Request, rsp server.Response) error { func (p *Proxy) ServeRequest(ctx context.Context, req server.Request, rsp server.Response) error {
// set default client
if p.Client == nil {
p.Client = client.DefaultClient
}
// service name // service name
service := req.Service() service := req.Service()
endpoint := req.Endpoint() endpoint := req.Endpoint()
@ -342,13 +235,24 @@ func NewProxy(opts ...options.Option) proxy.Proxy {
p.Client = c.(client.Client) p.Client = c.(client.Client)
} }
// set the default client
if p.Client == nil {
p.Client = client.DefaultClient
}
// get router // get router
r, ok := p.Options.Values().Get("proxy.router") r, ok := p.Options.Values().Get("proxy.router")
if ok { if ok {
p.Router = r.(router.Router) p.Router = r.(router.Router)
// TODO: should we advertise?
go p.Router.Advertise()
} }
// create default router and start it
if p.Router == nil {
p.Router = router.DefaultRouter
}
// routes cache
p.Routes = make(map[string]map[uint64]table.Route)
return p return p
} }