Skip to content

Commit 0cb1030

Browse files
Properly handle grpc dial errors in the throttler metric aggregation (vitessio#18073) (#155)
Signed-off-by: Arthur Schreiber <[email protected]> Signed-off-by: Mohamed Hamza <[email protected]> Co-authored-by: Arthur Schreiber <[email protected]>
1 parent fea1028 commit 0cb1030

File tree

2 files changed

+36
-4
lines changed

2 files changed

+36
-4
lines changed

go/vt/vttablet/tabletserver/throttle/base/throttle_metric.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ package base
4343

4444
import (
4545
"errors"
46-
"strings"
46+
"net"
47+
48+
"google.golang.org/grpc/codes"
49+
"google.golang.org/grpc/status"
4750
)
4851

4952
// MetricResult is what we expect our probes to return. This can be a numeric result, or
@@ -66,11 +69,20 @@ var ErrNoSuchMetric = errors.New("No such metric")
6669
var ErrInvalidCheckType = errors.New("Unknown throttler check type")
6770

6871
// IsDialTCPError sees if the given error indicates a TCP issue
69-
func IsDialTCPError(e error) bool {
70-
if e == nil {
72+
func IsDialTCPError(err error) bool {
73+
if err == nil {
7174
return false
7275
}
73-
return strings.HasPrefix(e.Error(), "dial tcp")
76+
77+
if s, ok := status.FromError(err); ok {
78+
return s.Code() == codes.Unavailable || s.Code() == codes.DeadlineExceeded
79+
}
80+
81+
switch err := err.(type) {
82+
case *net.OpError:
83+
return err.Op == "dial" && err.Net == "tcp"
84+
}
85+
return false
7486
}
7587

7688
type noHostsMetricResult struct{}

go/vt/vttablet/tabletserver/throttle/throttler_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,15 @@ import (
2828
"github.com/stretchr/testify/assert"
2929
"github.com/stretchr/testify/require"
3030

31+
"google.golang.org/grpc"
32+
"google.golang.org/grpc/credentials/insecure"
33+
34+
"vitess.io/vitess/go/vt/grpcclient"
3135
"vitess.io/vitess/go/vt/topo"
3236
"vitess.io/vitess/go/vt/vtenv"
3337
"vitess.io/vitess/go/vt/vttablet/tabletserver/connpool"
3438
"vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv"
39+
"vitess.io/vitess/go/vt/vttablet/tabletserver/throttle/base"
3540
"vitess.io/vitess/go/vt/vttablet/tabletserver/throttle/config"
3641
"vitess.io/vitess/go/vt/vttablet/tabletserver/throttle/mysql"
3742
"vitess.io/vitess/go/vt/vttablet/tmclient"
@@ -157,6 +162,21 @@ func newTestThrottler() *Throttler {
157162
return throttler
158163
}
159164

165+
func TestIsDialTCPError(t *testing.T) {
166+
// Verify that IsDialTCPError actually recognizes grpc dial errors
167+
cc, err := grpcclient.DialContext(context.Background(), ":0", true, grpc.WithTransportCredentials(insecure.NewCredentials()))
168+
require.NoError(t, err)
169+
defer cc.Close()
170+
171+
err = cc.Invoke(context.Background(), "/Fail", nil, nil)
172+
173+
require.True(t, base.IsDialTCPError(err))
174+
require.True(t, base.IsDialTCPError(fmt.Errorf("wrapped: %w", err)))
175+
176+
nonDialErr := fmt.Errorf("rpc error: code = NotFound desc = method not found")
177+
require.False(t, base.IsDialTCPError(nonDialErr))
178+
}
179+
160180
func TestIsAppThrottled(t *testing.T) {
161181
throttler := Throttler{
162182
throttledApps: cache.New(cache.NoExpiration, 0),

0 commit comments

Comments
 (0)