Deprecate client/selector (#1767)

* client/{grpc,rpc}: depricate selector (wip)

* {client,cmd}: remove client/selector

* deprecate client/selector

* router/static: fix lookup

* config/cmd: add support for legacy static selector flag

* config/cmd: add support for legacy dns selector flag
This commit is contained in:
ben-toogood 2020-07-01 17:06:59 +01:00 committed by Vasiliy Tolstov
parent ea93f93b18
commit 422fd980e9
2 changed files with 77 additions and 70 deletions

134
grpc.go
View File

@ -5,6 +5,7 @@ import (
"context" "context"
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"math/rand"
"net" "net"
"reflect" "reflect"
"strings" "strings"
@ -13,11 +14,11 @@ import (
"github.com/micro/go-micro/v2/broker" "github.com/micro/go-micro/v2/broker"
"github.com/micro/go-micro/v2/client" "github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/client/selector"
raw "github.com/micro/go-micro/v2/codec/bytes" raw "github.com/micro/go-micro/v2/codec/bytes"
"github.com/micro/go-micro/v2/errors" "github.com/micro/go-micro/v2/errors"
"github.com/micro/go-micro/v2/metadata" "github.com/micro/go-micro/v2/metadata"
"github.com/micro/go-micro/v2/registry" "github.com/micro/go-micro/v2/router"
"github.com/micro/go-micro/v2/selector"
pnet "github.com/micro/go-micro/v2/util/net" pnet "github.com/micro/go-micro/v2/util/net"
"google.golang.org/grpc" "google.golang.org/grpc"
@ -72,41 +73,59 @@ func (g *grpcClient) secure(addr string) grpc.DialOption {
return grpc.WithInsecure() return grpc.WithInsecure()
} }
func (g *grpcClient) next(request client.Request, opts client.CallOptions) (selector.Next, error) { // lookupRoute for a request using the router and then choose one using the selector
service, address, _ := pnet.Proxy(request.Service(), opts.Address) func (g *grpcClient) lookupRoute(req client.Request, opts client.CallOptions) (*router.Route, error) {
// check to see if the proxy has been set, if it has we don't need to lookup the routes; net.Proxy
// return remote address // returns a slice of addresses, so we'll use a random one. Eventually we should to use the
if len(address) > 0 { // selector for this.
return func() (*registry.Node, error) { service, addresses, _ := pnet.Proxy(req.Service(), opts.Address)
return &registry.Node{ if len(addresses) > 0 {
Address: address[0], return &router.Route{
}, nil Service: service,
Address: addresses[rand.Int()%len(addresses)],
}, nil }, nil
} }
// if the network was set, pass it to the selector // construct the router query
sopts := opts.SelectOptions query := []router.QueryOption{router.QueryService(req.Service())}
// if a custom network was requested, pass this to the router. By default the router will use it's
// own network, which is set during initialisation.
if len(opts.Network) > 0 { if len(opts.Network) > 0 {
sopts = append(sopts, selector.WithDomain(opts.Network)) query = append(query, router.QueryNetwork(opts.Network))
} }
// get next nodes from the selector // use the router passed as a call option, or fallback to the grpc clients router
next, err := g.opts.Selector.Select(service, sopts...) if opts.Router == nil {
if err != nil { opts.Router = g.opts.Router
if err == selector.ErrNotFound {
return nil, errors.InternalServerError("go.micro.client", "service %s: %s", service, err.Error())
}
return nil, errors.InternalServerError("go.micro.client", "error selecting %s node: %s", service, err.Error())
} }
return next, nil // lookup the routes which can be used to execute the request
routes, err := opts.Router.Lookup(query...)
if err == router.ErrRouteNotFound {
return nil, errors.InternalServerError("go.micro.client", "service %s: %s", req.Service(), err.Error())
} else if err != nil {
return nil, errors.InternalServerError("go.micro.client", "error getting next %s node: %s", req.Service(), err.Error())
}
// use the selector passed as a call option, or fallback to the grpc clients selector
if opts.Selector == nil {
opts.Selector = g.opts.Selector
}
// select the route to use for the request
if route, err := opts.Selector.Select(routes); err == selector.ErrNoneAvailable {
return nil, errors.InternalServerError("go.micro.client", "service %s: %s", req.Service(), err.Error())
} else if err != nil {
return nil, errors.InternalServerError("go.micro.client", "error getting next %s node: %s", req.Service(), err.Error())
} else {
return route, nil
}
} }
func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.Request, rsp interface{}, opts client.CallOptions) error { func (g *grpcClient) call(ctx context.Context, route *router.Route, req client.Request, rsp interface{}, opts client.CallOptions) error {
var header map[string]string var header map[string]string
address := node.Address
header = make(map[string]string) header = make(map[string]string)
if md, ok := metadata.FromContext(ctx); ok { if md, ok := metadata.FromContext(ctx); ok {
header = make(map[string]string, len(md)) header = make(map[string]string, len(md))
@ -137,7 +156,7 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R
grpcDialOptions := []grpc.DialOption{ grpcDialOptions := []grpc.DialOption{
grpc.WithTimeout(opts.DialTimeout), grpc.WithTimeout(opts.DialTimeout),
g.secure(address), g.secure(route.Address),
grpc.WithDefaultCallOptions( grpc.WithDefaultCallOptions(
grpc.MaxCallRecvMsgSize(maxRecvMsgSize), grpc.MaxCallRecvMsgSize(maxRecvMsgSize),
grpc.MaxCallSendMsgSize(maxSendMsgSize), grpc.MaxCallSendMsgSize(maxSendMsgSize),
@ -148,13 +167,13 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R
grpcDialOptions = append(grpcDialOptions, opts...) grpcDialOptions = append(grpcDialOptions, opts...)
} }
cc, err := g.pool.getConn(address, grpcDialOptions...) cc, err := g.pool.getConn(route.Address, grpcDialOptions...)
if err != nil { if err != nil {
return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err)) return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err))
} }
defer func() { defer func() {
// defer execution of release // defer execution of release
g.pool.release(address, cc, grr) g.pool.release(route.Address, cc, grr)
}() }()
ch := make(chan error, 1) ch := make(chan error, 1)
@ -180,11 +199,9 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R
return grr return grr
} }
func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client.Request, rsp interface{}, opts client.CallOptions) error { func (g *grpcClient) stream(ctx context.Context, route *router.Route, req client.Request, rsp interface{}, opts client.CallOptions) error {
var header map[string]string var header map[string]string
address := node.Address
if md, ok := metadata.FromContext(ctx); ok { if md, ok := metadata.FromContext(ctx); ok {
header = make(map[string]string, len(md)) header = make(map[string]string, len(md))
for k, v := range md { for k, v := range md {
@ -222,14 +239,14 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client
grpcDialOptions := []grpc.DialOption{ grpcDialOptions := []grpc.DialOption{
grpc.WithTimeout(opts.DialTimeout), grpc.WithTimeout(opts.DialTimeout),
g.secure(address), g.secure(route.Address),
} }
if opts := g.getGrpcDialOptions(); opts != nil { if opts := g.getGrpcDialOptions(); opts != nil {
grpcDialOptions = append(grpcDialOptions, opts...) grpcDialOptions = append(grpcDialOptions, opts...)
} }
cc, err := grpc.DialContext(dialCtx, address, grpcDialOptions...) cc, err := grpc.DialContext(dialCtx, route.Address, grpcDialOptions...)
if err != nil { if err != nil {
return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err)) return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err))
} }
@ -396,11 +413,6 @@ func (g *grpcClient) Call(ctx context.Context, req client.Request, rsp interface
opt(&callOpts) opt(&callOpts)
} }
next, err := g.next(req, callOpts)
if err != nil {
return err
}
// check if we already have a deadline // check if we already have a deadline
d, ok := ctx.Deadline() d, ok := ctx.Deadline()
if !ok { if !ok {
@ -443,19 +455,19 @@ func (g *grpcClient) Call(ctx context.Context, req client.Request, rsp interface
time.Sleep(t) time.Sleep(t)
} }
// select next node // lookup the route to send the reques to
node, err := next() route, err := g.lookupRoute(req, callOpts)
service := req.Service()
if err != nil { if err != nil {
if err == selector.ErrNotFound { return err
return errors.InternalServerError("go.micro.client", "service %s: %s", service, err.Error())
}
return errors.InternalServerError("go.micro.client", "error selecting %s node: %s", service, err.Error())
} }
// make the call // make the call
err = gcall(ctx, node, req, rsp, callOpts) err = gcall(ctx, route, req, rsp, callOpts)
g.opts.Selector.Mark(service, node, err)
// record the result of the call to inform future routing decisions
g.opts.Selector.Record(*route, err)
// try and transform the error to a go-micro error
if verr, ok := err.(*errors.Error); ok { if verr, ok := err.(*errors.Error); ok {
return verr return verr
} }
@ -503,11 +515,6 @@ func (g *grpcClient) Stream(ctx context.Context, req client.Request, opts ...cli
opt(&callOpts) opt(&callOpts)
} }
next, err := g.next(req, callOpts)
if err != nil {
return nil, err
}
// #200 - streams shouldn't have a request timeout set on the context // #200 - streams shouldn't have a request timeout set on the context
// should we noop right here? // should we noop right here?
@ -537,20 +544,25 @@ func (g *grpcClient) Stream(ctx context.Context, req client.Request, opts ...cli
time.Sleep(t) time.Sleep(t)
} }
node, err := next() // lookup the route to send the reques to
service := req.Service() route, err := g.lookupRoute(req, callOpts)
if err != nil { if err != nil {
if err == selector.ErrNotFound { return nil, err
return nil, errors.InternalServerError("go.micro.client", "service %s: %s", service, err.Error())
}
return nil, errors.InternalServerError("go.micro.client", "error selecting %s node: %s", service, err.Error())
} }
// make the call // make the call
stream := &grpcStream{} stream := &grpcStream{}
err = g.stream(ctx, node, req, stream, callOpts) err = g.stream(ctx, route, req, stream, callOpts)
g.opts.Selector.Mark(service, node, err) // record the result of the call to inform future routing decisions
g.opts.Selector.Record(*route, err)
// try and transform the error to a go-micro error
if verr, ok := err.(*errors.Error); ok {
return nil, verr
}
g.opts.Selector.Record(*route, err)
return stream, err return stream, err
} }
@ -577,7 +589,7 @@ func (g *grpcClient) Stream(ctx context.Context, req client.Request, opts ...cli
return rsp.stream, nil return rsp.stream, nil
} }
retry, rerr := callOpts.Retry(ctx, req, i, err) retry, rerr := callOpts.Retry(ctx, req, i, grr)
if rerr != nil { if rerr != nil {
return nil, rerr return nil, rerr
} }

View File

@ -6,10 +6,10 @@ import (
"testing" "testing"
"github.com/micro/go-micro/v2/client" "github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/client/selector"
"github.com/micro/go-micro/v2/errors" "github.com/micro/go-micro/v2/errors"
"github.com/micro/go-micro/v2/registry" "github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/registry/memory" "github.com/micro/go-micro/v2/registry/memory"
"github.com/micro/go-micro/v2/router"
pgrpc "google.golang.org/grpc" pgrpc "google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld" pb "google.golang.org/grpc/examples/helloworld/helloworld"
) )
@ -56,16 +56,11 @@ func TestGRPCClient(t *testing.T) {
}, },
}) })
// create selector // create router
se := selector.NewSelector( rtr := router.NewRouter(router.Registry(r))
selector.Registry(r),
)
// create client // create client
c := NewClient( c := NewClient(client.Router(rtr))
client.Registry(r),
client.Selector(se),
)
testMethods := []string{ testMethods := []string{
"/helloworld.Greeter/SayHello", "/helloworld.Greeter/SayHello",