diff --git a/picker_wrapper.go b/picker_wrapper.go index bf56faa76d3d..c0e568c607cf 100644 --- a/picker_wrapper.go +++ b/picker_wrapper.go @@ -151,6 +151,7 @@ func (pw *pickerWrapper) pick(ctx context.Context, failfast bool, info balancer. pickResult, err := p.Pick(info) if err != nil { if err == balancer.ErrNoSubConnAvailable { + lastPickErr = err continue } if st, ok := status.FromError(err); ok { diff --git a/picker_wrapper_test.go b/picker_wrapper_test.go index ba99a06b0f8c..7efd0bab257f 100644 --- a/picker_wrapper_test.go +++ b/picker_wrapper_test.go @@ -26,6 +26,7 @@ import ( "time" "google.golang.org/grpc/balancer" + "google.golang.org/grpc/balancer/base" "google.golang.org/grpc/codes" "google.golang.org/grpc/connectivity" "google.golang.org/grpc/internal/transport" @@ -74,6 +75,23 @@ func (s) TestBlockingPickTimeout(t *testing.T) { } } +func (s) TestBlockingPickErrNoSubConnAvailableTimeout(t *testing.T) { + bp := newPickerWrapper(nil) + ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond) + defer cancel() + + bp.updatePicker(base.NewErrPicker(balancer.ErrNoSubConnAvailable)) + var err error + if _, _, err = bp.pick(ctx, true, balancer.PickInfo{}); status.Code(err) != codes.DeadlineExceeded { + t.Errorf("bp.pick returned error %v, want DeadlineExceeded", err) + } + + serr, _ := status.FromError(err) + if serr.Message() != "latest balancer error: "+balancer.ErrNoSubConnAvailable.Error() { + t.Errorf("bp.pick returned error %v, want balancer.ErrNoSubConnAvailable", err) + } +} + func (s) TestBlockingPick(t *testing.T) { bp := newPickerWrapper(nil) // All goroutines should block because picker is nil in bp.