Skip to content

Commit 4d14098

Browse files
Allow Vitess HTTP client timeout override
2 parents 126e476 + 435c726 commit 4d14098

File tree

5 files changed

+123
-9
lines changed

5 files changed

+123
-9
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ require (
1313
github.com/patrickmn/go-cache v2.1.0+incompatible
1414
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563
1515
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed // indirect
16+
vitess.io/vitess v2.1.1+incompatible
1617
)

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp
1111
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1212
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
1313
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
14+
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
1415
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
1516
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
1617
github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
@@ -45,6 +46,9 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0
4546
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
4647
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
4748
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
49+
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
4850
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
4951
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed h1:uPxWBzB3+mlnjy9W58qY1j/cjyFjutgw/Vhan2zLy/A=
5052
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
53+
vitess.io/vitess v2.1.1+incompatible h1:nuuGHiWYWpudD3gOCLeGzol2EJ25e/u5Wer2wV1O130=
54+
vitess.io/vitess v2.1.1+incompatible/go.mod h1:h4qvkyNYTOC0xI+vcidSWoka0gQAZc9ZPHbkHo48gP0=

pkg/throttle/throttler.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,8 @@ func (throttler *Throttler) refreshMySQLInventory() error {
323323
log.Debugf("getting vitess data from %s", clusterSettings.VitessSettings.API)
324324
keyspace := clusterSettings.VitessSettings.Keyspace
325325
shard := clusterSettings.VitessSettings.Shard
326-
vtManager := vitess.NewManager(config.Settings().VitessHTTPTimeoutSec)
326+
timeout := time.Duration(config.Settings().VitessHTTPTimeoutSec) * time.Second
327+
vtManager := vitess.NewManager(timeout)
327328
tablets, err := vtManager.ParseTablets(clusterSettings.VitessSettings.API, keyspace, shard)
328329
if err != nil {
329330
return log.Errorf("Unable to get vitess hosts from %s, %s/%s: %+v", clusterSettings.VitessSettings.API, keyspace, shard, err)

pkg/vitess/api_client.go

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,20 @@ import (
77
"net/http"
88
"strings"
99
"time"
10+
11+
"vitess.io/vitess/go/vt/proto/topodata"
1012
)
1113

1214
// Tablet represents information about a running instance of vttablet.
1315
type Tablet struct {
14-
MysqlHostname string `json:"mysql_hostname,omitempty"`
15-
MysqlPort int32 `json:"mysql_port,omitempty"`
16+
MysqlHostname string `json:"mysql_hostname,omitempty"`
17+
MysqlPort int32 `json:"mysql_port,omitempty"`
18+
Type topodata.TabletType `json:"type,omitempty"`
19+
}
20+
21+
// IsValidReplica returns a bool reflecting if a tablet type is REPLICA
22+
func (t Tablet) IsValidReplica() bool {
23+
return t.Type == topodata.TabletType_REPLICA
1624
}
1725

1826
// Manager gathers info from Vitess
@@ -21,10 +29,12 @@ type Manager struct {
2129
}
2230

2331
// NewManager returns a new manager for Vitess
24-
func NewManager(timeoutSec int) *Manager {
25-
return &Manager{httpClient: http.Client{
26-
Timeout: time.Duration(timeoutSec) * time.Second,
27-
}}
32+
func NewManager(timeout time.Duration) *Manager {
33+
return &Manager{
34+
httpClient: http.Client{
35+
Timeout: timeout,
36+
},
37+
}
2838
}
2939

3040
func constructAPIURL(api string, keyspace string, shard string) (url string) {
@@ -37,8 +47,18 @@ func constructAPIURL(api string, keyspace string, shard string) (url string) {
3747
return url
3848
}
3949

50+
// filterReplicaTablets parses a list of tablets, returning replica tablets only
51+
func filterReplicaTablets(tablets []Tablet) (replicas []Tablet) {
52+
for _, tablet := range tablets {
53+
if tablet.IsValidReplica() {
54+
replicas = append(replicas, tablet)
55+
}
56+
}
57+
return replicas
58+
}
59+
4060
// ParseTablets reads from vitess /api/ks_tablets/<keyspace>/[shard] and returns a
41-
// tblet (mysql_hostname, mysql_port) listing
61+
// listing (mysql_hostname, mysql_port, type) of REPLICA tablets
4262
func (m *Manager) ParseTablets(api string, keyspace string, shard string) (tablets []Tablet, err error) {
4363
url := constructAPIURL(api, keyspace, shard)
4464
resp, err := m.httpClient.Get(url)
@@ -53,5 +73,5 @@ func (m *Manager) ParseTablets(api string, keyspace string, shard string) (table
5373
}
5474

5575
err = json.Unmarshal(body, &tablets)
56-
return tablets, err
76+
return filterReplicaTablets(tablets), err
5777
}

pkg/vitess/api_client_test.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package vitess
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"net/http"
7+
"net/http/httptest"
8+
"testing"
9+
"time"
10+
11+
"vitess.io/vitess/go/vt/proto/topodata"
12+
)
13+
14+
func TestParseTablets(t *testing.T) {
15+
vitessApi := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
16+
switch r.URL.String() {
17+
case "/api/keyspace/test/tablets/00":
18+
data, _ := json.Marshal([]Tablet{
19+
{
20+
MysqlHostname: "master",
21+
Type: topodata.TabletType_MASTER,
22+
},
23+
{
24+
MysqlHostname: "replica",
25+
Type: topodata.TabletType_REPLICA,
26+
},
27+
{
28+
MysqlHostname: "spare",
29+
Type: topodata.TabletType_SPARE,
30+
},
31+
{
32+
MysqlHostname: "batch",
33+
Type: topodata.TabletType_BATCH,
34+
},
35+
{
36+
MysqlHostname: "backup",
37+
Type: topodata.TabletType_BACKUP,
38+
},
39+
{
40+
41+
MysqlHostname: "restore",
42+
Type: topodata.TabletType_RESTORE,
43+
},
44+
})
45+
fmt.Fprint(w, string(data))
46+
default:
47+
w.WriteHeader(http.StatusNotFound)
48+
fmt.Fprint(w, "[]")
49+
}
50+
}))
51+
defer vitessApi.Close()
52+
53+
m := NewManager(time.Duration(1) * time.Second)
54+
55+
t.Run("success", func(t *testing.T) {
56+
tablets, err := m.ParseTablets(vitessApi.URL, "test", "00")
57+
if err != nil {
58+
t.Fatalf("Expected no error, got %q", err)
59+
}
60+
61+
if len(tablets) != 1 {
62+
t.Fatalf("Expected 1 tablet, got %d", len(tablets))
63+
}
64+
65+
if tablets[0].MysqlHostname != "replica" {
66+
t.Fatalf("Expected hostname %q, got %q", "replica", tablets[0].MysqlHostname)
67+
}
68+
})
69+
70+
t.Run("not-found", func(t *testing.T) {
71+
tablets, err := m.ParseTablets(vitessApi.URL, "not-found", "00")
72+
if err != nil {
73+
t.Fatalf("Expected no error, got %q", err)
74+
}
75+
76+
if len(tablets) > 0 {
77+
t.Fatalf("Expected 0 tablets, got %d", len(tablets))
78+
}
79+
})
80+
81+
t.Run("failed", func(t *testing.T) {
82+
vitessApi.Close() // kill the mock vitess API
83+
_, err := m.ParseTablets(vitessApi.URL, "fail", "00")
84+
if err == nil {
85+
t.Fatal("Expected error, got nil")
86+
}
87+
})
88+
}

0 commit comments

Comments
 (0)