diff --git a/clientconn.go b/clientconn.go index 261d3e38..e8d95b43 100644 --- a/clientconn.go +++ b/clientconn.go @@ -108,9 +108,10 @@ type dialOptions struct { // balancer, and also by WithBalancerName dial option. balancerBuilder balancer.Builder // This is to support grpclb. - resolverBuilder resolver.Builder - waitForHandshake bool - channelzParentID int64 + resolverBuilder resolver.Builder + waitForHandshake bool + channelzParentID int64 + disableServiceConfig bool } const ( @@ -416,6 +417,15 @@ func WithChannelzParentID(id int64) DialOption { } } +// WithDisableServiceConfig returns a DialOption that causes grpc to ignore any +// service config provided by the resolver and provides a hint to the resolver +// to not fetch service configs. +func WithDisableServiceConfig() DialOption { + return func(o *dialOptions) { + o.disableServiceConfig = true + } +} + // Dial creates a client connection to the given target. func Dial(target string, opts ...DialOption) (*ClientConn, error) { return DialContext(context.Background(), target, opts...) @@ -1002,6 +1012,9 @@ func (cc *ClientConn) getTransport(ctx context.Context, failfast bool) (transpor // handleServiceConfig parses the service config string in JSON format to Go native // struct ServiceConfig, and store both the struct and the JSON string in ClientConn. func (cc *ClientConn) handleServiceConfig(js string) error { + if cc.dopts.disableServiceConfig { + return nil + } sc, err := parseServiceConfig(js) if err != nil { return err diff --git a/clientconn_test.go b/clientconn_test.go index 5dde548b..4c5bf8bc 100644 --- a/clientconn_test.go +++ b/clientconn_test.go @@ -646,3 +646,32 @@ func TestClientUpdatesParamsAfterGoAway(t *testing.T) { t.Fatalf("cc.dopts.copts.Keepalive.Time = %v , want 100ms", v) } } + +func TestDisableServiceConfigOption(t *testing.T) { + r, cleanup := manual.GenerateAndRegisterManualResolver() + defer cleanup() + addr := r.Scheme() + ":///non.existent" + cc, err := Dial(addr, WithInsecure(), WithDisableServiceConfig()) + if err != nil { + t.Fatalf("Dial(%s, _) = _, %v, want _, ", addr, err) + } + defer cc.Close() + r.NewServiceConfig(`{ + "methodConfig": [ + { + "name": [ + { + "service": "foo", + "method": "Bar" + } + ], + "waitForReady": true + } + ] +}`) + time.Sleep(1 * time.Second) + m := cc.GetMethodConfig("/foo/Bar") + if m.WaitForReady != nil { + t.Fatalf("want: method (\"/foo/bar/\") config to be empty, got: %v", m) + } +} diff --git a/resolver/dns/dns_resolver.go b/resolver/dns/dns_resolver.go index 8ab6e288..c1cabfc9 100644 --- a/resolver/dns/dns_resolver.go +++ b/resolver/dns/dns_resolver.go @@ -90,14 +90,15 @@ func (b *dnsBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts // DNS address (non-IP). ctx, cancel := context.WithCancel(context.Background()) d := &dnsResolver{ - freq: b.freq, - host: host, - port: port, - ctx: ctx, - cancel: cancel, - cc: cc, - t: time.NewTimer(0), - rn: make(chan struct{}, 1), + freq: b.freq, + host: host, + port: port, + ctx: ctx, + cancel: cancel, + cc: cc, + t: time.NewTimer(0), + rn: make(chan struct{}, 1), + disableServiceConfig: opts.DisableServiceConfig, } d.wg.Add(1) @@ -160,7 +161,8 @@ type dnsResolver struct { // If Close() doesn't wait for watcher() goroutine finishes, race detector sometimes // will warns lookup (READ the lookup function pointers) inside watcher() goroutine // has data race with replaceNetFunc (WRITE the lookup function pointers). - wg sync.WaitGroup + wg sync.WaitGroup + disableServiceConfig bool } // ResolveNow invoke an immediate resolution of the target that this dnsResolver watches. @@ -205,7 +207,7 @@ func (d *dnsResolver) lookupSRV() []resolver.Address { for _, s := range srvs { lbAddrs, err := lookupHost(d.ctx, s.Target) if err != nil { - grpclog.Warningf("grpc: failed load balancer address dns lookup due to %v.\n", err) + grpclog.Infof("grpc: failed load balancer address dns lookup due to %v.\n", err) continue } for _, a := range lbAddrs { @@ -224,7 +226,7 @@ func (d *dnsResolver) lookupSRV() []resolver.Address { func (d *dnsResolver) lookupTXT() string { ss, err := lookupTXT(d.ctx, d.host) if err != nil { - grpclog.Warningf("grpc: failed dns TXT record lookup due to %v.\n", err) + grpclog.Infof("grpc: failed dns TXT record lookup due to %v.\n", err) return "" } var res string @@ -263,6 +265,9 @@ func (d *dnsResolver) lookup() ([]resolver.Address, string) { newAddrs := d.lookupSRV() // Support fallback to non-balancer address. newAddrs = append(newAddrs, d.lookupHost()...) + if d.disableServiceConfig { + return newAddrs, "" + } sc := d.lookupTXT() return newAddrs, canaryingSC(sc) } diff --git a/resolver/dns/dns_resolver_test.go b/resolver/dns/dns_resolver_test.go index 41a9ecb9..3e82db67 100644 --- a/resolver/dns/dns_resolver_test.go +++ b/resolver/dns/dns_resolver_test.go @@ -892,3 +892,45 @@ func TestResolveFunc(t *testing.T) { } } } + +func TestDisableServiceConfig(t *testing.T) { + defer leakcheck.Check(t) + tests := []struct { + target string + scWant string + disableServiceConfig bool + }{ + { + "foo.bar.com", + generateSC("foo.bar.com"), + false, + }, + { + "foo.bar.com", + "", + true, + }, + } + + for _, a := range tests { + b := NewBuilder() + cc := &testClientConn{target: a.target} + r, err := b.Build(resolver.Target{Endpoint: a.target}, cc, resolver.BuildOption{DisableServiceConfig: a.disableServiceConfig}) + if err != nil { + t.Fatalf("%v\n", err) + } + var cnt int + var sc string + for { + sc, cnt = cc.getSc() + if cnt > 0 { + break + } + time.Sleep(time.Millisecond) + } + if !reflect.DeepEqual(a.scWant, sc) { + t.Errorf("Resolved service config of target: %q = %+v, want %+v\n", a.target, sc, a.scWant) + } + r.Close() + } +} diff --git a/resolver/resolver.go b/resolver/resolver.go index 6b90dbab..506afac8 100644 --- a/resolver/resolver.go +++ b/resolver/resolver.go @@ -90,6 +90,8 @@ type Address struct { // BuildOption includes additional information for the builder to create // the resolver. type BuildOption struct { + // DisableServiceConfig indicates whether resolver should fetch service config data. + DisableServiceConfig bool } // ClientConn contains the callbacks for resolver to notify any updates diff --git a/resolver_conn_wrapper.go b/resolver_conn_wrapper.go index 2c91b038..1b493db2 100644 --- a/resolver_conn_wrapper.go +++ b/resolver_conn_wrapper.go @@ -84,7 +84,7 @@ func newCCResolverWrapper(cc *ClientConn) (*ccResolverWrapper, error) { } var err error - ccr.resolver, err = rb.Build(cc.parsedTarget, ccr, resolver.BuildOption{}) + ccr.resolver, err = rb.Build(cc.parsedTarget, ccr, resolver.BuildOption{DisableServiceConfig: cc.dopts.disableServiceConfig}) if err != nil { return nil, err }