Skip to content

Commit 5ec0994

Browse files
Merge pull request #1268 from michelle192837/retry
Add retry when snapshotting configuration.
2 parents c4fba0a + 6c9698a commit 5ec0994

12 files changed

Lines changed: 188 additions & 33 deletions

File tree

config/cache_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,16 @@ func Test_ReadGCS(t *testing.T) {
100100
t.Run(test.name, func(t *testing.T) {
101101
cache = test.currentCache
102102
client := fake.Client{
103-
Opener: fake.Opener{},
103+
Opener: fake.Opener{
104+
Paths: map[gcs.Path]fake.Object{},
105+
},
104106
}
105107
expectedAttrs := &storage.ReaderObjectAttrs{
106108
LastModified: test.remoteLastModified,
107109
Generation: test.remoteGeneration,
108110
}
109111

110-
client.Opener[mustPath("gs://example")] = fake.Object{
112+
client.Opener.Paths[mustPath("gs://example")] = fake.Object{
111113
Data: string(test.remoteData),
112114
Attrs: expectedAttrs,
113115
}

config/snapshot/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ go_library(
99
"//config:go_default_library",
1010
"//pb/config:go_default_library",
1111
"//util/gcs:go_default_library",
12+
"@com_github_sethvargo_go_retry//:go_default_library",
1213
"@com_github_sirupsen_logrus//:go_default_library",
1314
"@com_google_cloud_go_storage//:go_default_library",
1415
],

config/snapshot/config_snapshot.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/GoogleCloudPlatform/testgrid/config"
2626
configpb "github.com/GoogleCloudPlatform/testgrid/pb/config"
2727
"github.com/GoogleCloudPlatform/testgrid/util/gcs"
28+
"github.com/sethvargo/go-retry"
2829
"github.com/sirupsen/logrus"
2930
)
3031

@@ -119,6 +120,22 @@ func updateHash(ctx context.Context, client gcs.Opener, configPath gcs.Path) (*C
119120
}
120121

121122
func fetchConfig(ctx context.Context, client gcs.Opener, configPath gcs.Path) (*configpb.Configuration, *storage.ReaderObjectAttrs, error) {
123+
backoff := retry.WithMaxRetries(2, retry.NewExponential(5*time.Second))
124+
125+
var cfg *configpb.Configuration
126+
var attrs *storage.ReaderObjectAttrs
127+
err := retry.Do(ctx, backoff, func(innerCtx context.Context) error {
128+
var onceErr error
129+
cfg, attrs, onceErr = fetchConfigOnce(innerCtx, client, configPath)
130+
if onceErr != nil {
131+
return retry.RetryableError(onceErr)
132+
}
133+
return nil
134+
})
135+
return cfg, attrs, err
136+
}
137+
138+
func fetchConfigOnce(ctx context.Context, client gcs.Opener, configPath gcs.Path) (*configpb.Configuration, *storage.ReaderObjectAttrs, error) {
122139
r, attrs, err := client.Open(ctx, configPath)
123140
if err != nil {
124141
return nil, nil, fmt.Errorf("open: %w", err)

config/snapshot/config_snapshot_test.go

Lines changed: 89 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func TestObserve_OnInit(t *testing.T) {
7373
defer cancel()
7474

7575
client := fakeClient()
76-
client.Opener[*path] = fake.Object{
76+
client.Opener.Paths[*path] = fake.Object{
7777
Data: string(mustMarshalConfig(test.config)),
7878
Attrs: &storage.ReaderObjectAttrs{
7979
Generation: test.configGeneration,
@@ -108,6 +108,87 @@ func TestObserve_OnInit(t *testing.T) {
108108
}
109109
}
110110

111+
func TestObserve_OnInitRetry(t *testing.T) {
112+
tests := []struct {
113+
name string
114+
config *configpb.Configuration
115+
configGeneration int64
116+
openErr error
117+
openOnRetry bool
118+
expectInitial *configpb.Dashboard
119+
expectError bool
120+
}{
121+
{
122+
name: "Reads config on retry",
123+
config: &configpb.Configuration{
124+
Dashboards: []*configpb.Dashboard{
125+
{
126+
Name: "dashboard",
127+
},
128+
},
129+
},
130+
openErr: errors.New("fake error"),
131+
openOnRetry: true,
132+
expectInitial: &configpb.Dashboard{
133+
Name: "dashboard",
134+
},
135+
},
136+
{
137+
name: "Returns error if config isn't present on retry",
138+
openErr: errors.New("fake error"),
139+
expectError: true,
140+
},
141+
}
142+
143+
path, err := gcs.NewPath("gs://config/example")
144+
if err != nil {
145+
t.Fatal("could not path")
146+
}
147+
148+
for _, test := range tests {
149+
t.Run(test.name, func(t *testing.T) {
150+
ctx, cancel := context.WithCancel(context.Background())
151+
defer cancel()
152+
153+
client := fakeClient()
154+
client.Opener.Paths[*path] = fake.Object{
155+
Data: string(mustMarshalConfig(test.config)),
156+
Attrs: &storage.ReaderObjectAttrs{
157+
Generation: 1,
158+
},
159+
OpenErr: test.openErr,
160+
OpenOnRetry: test.openOnRetry,
161+
}
162+
client.Stater[*path] = fake.Stat{
163+
Attrs: storage.ObjectAttrs{
164+
Generation: 1,
165+
},
166+
}
167+
168+
snaps, err := Observe(ctx, nil, client, *path, nil)
169+
170+
if !test.expectError && err != nil {
171+
t.Errorf("Observe() got unexpected error: %v", err)
172+
} else if test.expectError && err == nil {
173+
t.Errorf("Observe() did not error as expected.")
174+
}
175+
176+
if test.expectInitial == nil {
177+
return
178+
}
179+
180+
select {
181+
case cs := <-snaps:
182+
if result := cs.Dashboards["dashboard"]; !proto.Equal(result, test.expectInitial) {
183+
t.Errorf("got dashboard %v, expected %v", result, test.expectInitial)
184+
}
185+
case <-time.After(30 * time.Second):
186+
t.Error("expected an initial snapshot, but got none")
187+
}
188+
})
189+
}
190+
}
191+
111192
func TestObserve_OnTick(t *testing.T) {
112193
tests := []struct {
113194
name string
@@ -169,7 +250,7 @@ func TestObserve_OnTick(t *testing.T) {
169250
defer cancel()
170251

171252
client := fakeClient()
172-
client.Opener[*path] = fake.Object{
253+
client.Opener.Paths[*path] = fake.Object{
173254
Data: string(mustMarshalConfig(initialConfig)),
174255
Attrs: &storage.ReaderObjectAttrs{
175256
Generation: 1,
@@ -190,7 +271,7 @@ func TestObserve_OnTick(t *testing.T) {
190271
<-snaps
191272

192273
// Change the config
193-
client.Opener[*path] = fake.Object{
274+
client.Opener.Paths[*path] = fake.Object{
194275
Data: string(mustMarshalConfig(test.config)),
195276
Attrs: &storage.ReaderObjectAttrs{
196277
Generation: test.configGeneration,
@@ -350,7 +431,7 @@ func TestObserve_Data(t *testing.T) {
350431
defer cancel()
351432

352433
client := fakeClient()
353-
client.Opener[*path] = fake.Object{
434+
client.Opener.Paths[*path] = fake.Object{
354435
Data: string(mustMarshalConfig(test.config)),
355436
Attrs: &storage.ReaderObjectAttrs{
356437
Generation: 1,
@@ -394,7 +475,10 @@ func fakeClient() *fake.ConditionalClient {
394475
Uploader: fake.Uploader{},
395476
Client: fake.Client{
396477
Lister: fake.Lister{},
397-
Opener: fake.Opener{},
478+
Opener: fake.Opener{
479+
Paths: map[gcs.Path]fake.Object{},
480+
Lock: &sync.RWMutex{},
481+
},
398482
},
399483
Stater: fake.Stater{},
400484
},

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ require (
1717
github.com/hashicorp/go-multierror v1.1.1
1818
github.com/prometheus/client_golang v1.11.1
1919
github.com/prometheus/client_model v0.3.0
20+
github.com/sethvargo/go-retry v0.2.4
2021
github.com/sirupsen/logrus v1.9.3
2122
google.golang.org/api v0.134.0
2223
google.golang.org/genproto v0.0.0-20230731193218-e0aa005b6bdf

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,8 @@ github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDN
11521152
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
11531153
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
11541154
github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk=
1155+
github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08Ocec=
1156+
github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw=
11551157
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
11561158
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
11571159
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=

pkg/updater/persist_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,9 @@ func TestFixPersistent(t *testing.T) {
223223
Uploader: fake.Uploader{},
224224
Client: fake.Client{
225225
Opener: fake.Opener{
226-
*path: tc.currently,
226+
Paths: map[gcs.Path]fake.Object{
227+
*path: tc.currently,
228+
},
227229
},
228230
},
229231
}

pkg/updater/read_test.go

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,7 +1178,10 @@ func TestReadColumns(t *testing.T) {
11781178
defer cancel()
11791179
client := fakeClient{
11801180
Lister: fake.Lister{},
1181-
Opener: fake.Opener{},
1181+
Opener: fake.Opener{
1182+
Paths: map[gcs.Path]fake.Object{},
1183+
Lock: &sync.RWMutex{},
1184+
},
11821185
}
11831186

11841187
builds := addBuilds(&client, path, tc.builds...)
@@ -1668,7 +1671,10 @@ func TestReadResult(t *testing.T) {
16681671
defer cancel()
16691672
client := fakeClient{
16701673
Lister: fake.Lister{},
1671-
Opener: fake.Opener{},
1674+
Opener: fake.Opener{
1675+
Paths: map[gcs.Path]fake.Object{},
1676+
Lock: &sync.RWMutex{},
1677+
},
16721678
}
16731679

16741680
fi := fakeIterator{}
@@ -1680,7 +1686,7 @@ func TestReadResult(t *testing.T) {
16801686
fi.Objects = append(fi.Objects, storage.ObjectAttrs{
16811687
Name: p.Object(),
16821688
})
1683-
client.Opener[*p] = fo
1689+
client.Opener.Paths[*p] = fo
16841690
}
16851691
client.Lister[path] = fi
16861692

@@ -1850,7 +1856,9 @@ func TestReadSuites(t *testing.T) {
18501856
defer cancel()
18511857
client := fakeClient{
18521858
Lister: fake.Lister{},
1853-
Opener: fake.Opener{},
1859+
Opener: fake.Opener{
1860+
Paths: map[gcs.Path]fake.Object{},
1861+
},
18541862
}
18551863

18561864
fi := fakeIterator{
@@ -1864,7 +1872,7 @@ func TestReadSuites(t *testing.T) {
18641872
fi.Objects = append(fi.Objects, storage.ObjectAttrs{
18651873
Name: p.Object(),
18661874
})
1867-
client.Opener[*p] = fo
1875+
client.Opener.Paths[*p] = fo
18681876
}
18691877
client.Lister[path] = fi
18701878

@@ -1898,6 +1906,10 @@ func TestReadSuites(t *testing.T) {
18981906
}
18991907

19001908
func addBuilds(fc *fake.Client, path gcs.Path, s ...fakeBuild) []gcs.Build {
1909+
if fc.Opener.Lock != nil {
1910+
fc.Opener.Lock.Lock()
1911+
defer fc.Opener.Lock.Unlock()
1912+
}
19011913
var builds []gcs.Build
19021914
for _, build := range s {
19031915
buildPath := resolveOrDie(&path, build.id+"/")
@@ -1909,25 +1921,25 @@ func addBuilds(fc *fake.Client, path gcs.Path, s ...fakeBuild) []gcs.Build {
19091921
fi.Objects = append(fi.Objects, storage.ObjectAttrs{
19101922
Name: p.Object(),
19111923
})
1912-
fc.Opener[*p] = *build.podInfo
1924+
fc.Opener.Paths[*p] = *build.podInfo
19131925
}
19141926
if build.started != nil {
19151927
p := resolveOrDie(buildPath, "started.json")
19161928
fi.Objects = append(fi.Objects, storage.ObjectAttrs{
19171929
Name: p.Object(),
19181930
})
1919-
fc.Opener[*p] = *build.started
1931+
fc.Opener.Paths[*p] = *build.started
19201932
}
19211933
if build.finished != nil {
19221934
p := resolveOrDie(buildPath, "finished.json")
19231935
fi.Objects = append(fi.Objects, storage.ObjectAttrs{
19241936
Name: p.Object(),
19251937
})
1926-
fc.Opener[*p] = *build.finished
1938+
fc.Opener.Paths[*p] = *build.finished
19271939
}
19281940
if len(build.passed)+len(build.failed) > 0 {
19291941
p := resolveOrDie(buildPath, "junit_automatic.xml")
1930-
fc.Opener[*p] = fake.Object{Data: makeJunit(build.passed, build.failed)}
1942+
fc.Opener.Paths[*p] = fake.Object{Data: makeJunit(build.passed, build.failed)}
19311943
fi.Objects = append(fi.Objects, storage.ObjectAttrs{
19321944
Name: p.Object(),
19331945
})
@@ -1937,7 +1949,7 @@ func addBuilds(fc *fake.Client, path gcs.Path, s ...fakeBuild) []gcs.Build {
19371949
fi.Objects = append(fi.Objects, storage.ObjectAttrs{
19381950
Name: p.Object(),
19391951
})
1940-
fc.Opener[*p] = fo
1952+
fc.Opener.Paths[*p] = fo
19411953
}
19421954
fc.Lister[*buildPath] = fi
19431955
}

pkg/updater/updater_test.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -389,13 +389,15 @@ func TestUpdate(t *testing.T) {
389389
Uploader: fakeUploader{},
390390
Client: fakeClient{
391391
Lister: fakeLister{},
392-
Opener: fakeOpener{},
392+
Opener: fakeOpener{
393+
Paths: map[gcs.Path]fake.Object{},
394+
},
393395
},
394396
},
395397
Lock: &sync.RWMutex{},
396398
}
397399

398-
client.Opener[configPath] = fakeObject{
400+
client.Opener.Paths[configPath] = fakeObject{
399401
Data: func() string {
400402
b, err := config.MarshalBytes(tc.config)
401403
if err != nil {
@@ -2028,13 +2030,15 @@ func TestInflateDropAppend(t *testing.T) {
20282030
Uploader: fakeUploader{},
20292031
Client: fakeClient{
20302032
Lister: fakeLister{},
2031-
Opener: fakeOpener{},
2033+
Opener: fakeOpener{
2034+
Paths: map[gcs.Path]fake.Object{},
2035+
},
20322036
},
20332037
},
20342038
}
20352039

20362040
if tc.current != nil {
2037-
client.Opener[uploadPath] = *tc.current
2041+
client.Opener.Paths[uploadPath] = *tc.current
20382042
}
20392043

20402044
buildsPath := newPathOrDie("gs://" + tc.group.GcsPrefix)
@@ -2079,13 +2083,15 @@ func TestInflateDropAppend(t *testing.T) {
20792083
}
20802084
t.Logf("InflateDropAppend() generated a binary diff (-want +got):\n%s", diff)
20812085
fakeDownloader := fakeOpener{
2082-
uploadPath: {Data: string(actual[uploadPath].Buf)},
2086+
Paths: map[gcs.Path]fake.Object{
2087+
uploadPath: {Data: string(actual[uploadPath].Buf)},
2088+
},
20832089
}
20842090
actualGrid, _, err := gcs.DownloadGrid(ctx, fakeDownloader, uploadPath)
20852091
if err != nil {
20862092
t.Errorf("actual gcs.DownloadGrid() got unexpected error: %v", err)
20872093
}
2088-
fakeDownloader[uploadPath] = fakeObject{Data: string(tc.expected.Buf)}
2094+
fakeDownloader.Paths[uploadPath] = fakeObject{Data: string(tc.expected.Buf)}
20892095
expectedGrid, _, err := gcs.DownloadGrid(ctx, fakeDownloader, uploadPath)
20902096
if err != nil {
20912097
t.Errorf("expected gcs.DownloadGrid() got unexpected error: %v", err)

repos.bzl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,6 +1227,14 @@ def go_repositories():
12271227
sum = "h1:K1Xf3bKttbF+koVGaX5xngRIZ5bVjbmPnaxE/dR08uY=",
12281228
version = "v0.0.0-20201230142125-a7e3863a1245",
12291229
)
1230+
go_repository(
1231+
name = "com_github_sethvargo_go_retry",
1232+
build_file_generation = "on",
1233+
build_file_proto_mode = "disable",
1234+
importpath = "github.com/sethvargo/go-retry",
1235+
sum = "h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08Ocec=",
1236+
version = "v0.2.4",
1237+
)
12301238

12311239
go_repository(
12321240
name = "com_github_sirupsen_logrus",

0 commit comments

Comments
 (0)