Skip to content

Commit a14e7c5

Browse files
committed
Enter transient failure on resolver creation failure
1 parent 8110884 commit a14e7c5

File tree

3 files changed

+35
-13
lines changed

3 files changed

+35
-13
lines changed

clientconn.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -357,9 +357,7 @@ func (cc *ClientConn) exitIdleMode() (err error) {
357357
// This needs to be called without cc.mu because this builds a new resolver
358358
// which might update state or report error inline, which would then need to
359359
// acquire cc.mu.
360-
if err := cc.resolverWrapper.start(); err != nil {
361-
return err
362-
}
360+
cc.resolverWrapper.start()
363361

364362
cc.addTraceEvent("exiting idle mode")
365363
return nil

clientconn_parsed_target_test.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"time"
2828

2929
"github.com/google/go-cmp/cmp"
30+
"google.golang.org/grpc/connectivity"
3031
"google.golang.org/grpc/credentials/insecure"
3132
"google.golang.org/grpc/internal"
3233
"google.golang.org/grpc/internal/testutils"
@@ -185,6 +186,8 @@ func (s) TestParsedTarget_Success_WithoutCustomDialer(t *testing.T) {
185186
}
186187

187188
func (s) TestParsedTarget_Failure_WithoutCustomDialer(t *testing.T) {
189+
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
190+
defer cancel()
188191
targets := []string{
189192
"",
190193
"unix://a/b/c",
@@ -195,10 +198,13 @@ func (s) TestParsedTarget_Failure_WithoutCustomDialer(t *testing.T) {
195198

196199
for _, target := range targets {
197200
t.Run(target, func(t *testing.T) {
198-
if cc, err := Dial(target, WithTransportCredentials(insecure.NewCredentials())); err == nil {
199-
defer cc.Close()
200-
t.Fatalf("Dial(%q) succeeded cc.parsedTarget = %+v, expected to fail", target, cc.parsedTarget)
201+
cc, err := NewClient(target, WithTransportCredentials(insecure.NewCredentials()))
202+
if err != nil {
203+
t.Fatalf("NewClient(%q) failed: %v", target, err)
201204
}
205+
defer cc.Close()
206+
cc.Connect()
207+
testutils.AwaitState(ctx, t, cc, connectivity.TransientFailure)
202208
})
203209
}
204210
}

resolver_wrapper.go

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package grpc
2020

2121
import (
2222
"context"
23+
"fmt"
2324
"strings"
2425
"sync"
2526

@@ -62,11 +63,15 @@ func newCCResolverWrapper(cc *ClientConn) *ccResolverWrapper {
6263
}
6364
}
6465

65-
// start builds the name resolver using the resolver.Builder in cc and returns
66-
// any error encountered. It must always be the first operation performed on
67-
// any newly created ccResolverWrapper, except that close may be called instead.
68-
func (ccr *ccResolverWrapper) start() error {
69-
errCh := make(chan error)
66+
// start builds the name resolver using the resolver.Builder in cc.
67+
// If an error is encountered, it will report the error to the load balancing
68+
// policy via cc.ReportError(). This action allows the policy to set the channel
69+
// state to TransientFailure and ensures the error is propagated to new RPCs,
70+
// causing them to fail.
71+
// It must always be the first operation performed on any newly created
72+
// ccResolverWrapper, except that close may be called instead.
73+
func (ccr *ccResolverWrapper) start() {
74+
doneCh := make(chan struct{})
7075
ccr.serializer.TrySchedule(func(ctx context.Context) {
7176
if ctx.Err() != nil {
7277
return
@@ -90,11 +95,24 @@ func (ccr *ccResolverWrapper) start() error {
9095
} else {
9196
ccr.resolver, err = delegatingresolver.New(ccr.cc.parsedTarget, ccr, opts, ccr.cc.resolverBuilder, ccr.cc.dopts.enableLocalDNSResolution)
9297
}
93-
errCh <- err
98+
99+
if err != nil {
100+
ccr.resolver = &nopResolver{}
101+
ccr.ReportError(fmt.Errorf("resolver creation failed: %v", err))
102+
}
103+
104+
doneCh <- struct{}{}
94105
})
95-
return <-errCh
106+
<-doneCh
96107
}
97108

109+
type nopResolver struct {
110+
}
111+
112+
func (*nopResolver) ResolveNow(resolver.ResolveNowOptions) {}
113+
114+
func (*nopResolver) Close() {}
115+
98116
func (ccr *ccResolverWrapper) resolveNow(o resolver.ResolveNowOptions) {
99117
ccr.serializer.TrySchedule(func(ctx context.Context) {
100118
if ctx.Err() != nil || ccr.resolver == nil {

0 commit comments

Comments
 (0)