Skip to content

Commit cf584e5

Browse files
committed
Retry HTTP2 INTERNAL_ERRORs
1 parent 8dcd39a commit cf584e5

File tree

3 files changed

+66
-10
lines changed

3 files changed

+66
-10
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
github.com/gofrs/flock v0.8.1
88
github.com/spf13/pflag v1.0.5
99
github.com/stretchr/testify v1.8.4
10+
golang.org/x/net v0.20.0
1011
golang.org/x/sync v0.6.0
1112
)
1213

@@ -16,6 +17,7 @@ require (
1617
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
1718
github.com/pmezard/go-difflib v1.0.0 // indirect
1819
golang.org/x/sys v0.16.0 // indirect
20+
golang.org/x/text v0.14.0 // indirect
1921
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
2022
gopkg.in/yaml.v3 v3.0.1 // indirect
2123
)

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,14 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
1717
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
1818
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
1919
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
20+
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
21+
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
2022
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
2123
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
2224
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
2325
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
26+
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
27+
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
2428
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
2529
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
2630
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

pkg/geoipupdate/geoip_updater.go

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@ package geoipupdate
55
import (
66
"context"
77
"encoding/json"
8+
"errors"
89
"fmt"
910
"log"
1011
"os"
1112
"sync"
1213
"time"
1314

15+
"github.com/cenkalti/backoff/v4"
16+
"golang.org/x/net/http2"
17+
1418
"github.com/maxmind/geoipupdate/v6/pkg/geoipupdate/database"
1519
"github.com/maxmind/geoipupdate/v6/pkg/geoipupdate/internal"
1620
)
@@ -85,20 +89,11 @@ func (c *Client) Run(ctx context.Context) error {
8589
for _, editionID := range c.config.EditionIDs {
8690
editionID := editionID
8791
processFunc := func(ctx context.Context) error {
88-
editionHash, err := writer.GetHash(editionID)
92+
edition, err := c.downloadEdition(ctx, editionID, reader, writer)
8993
if err != nil {
9094
return err
9195
}
9296

93-
edition, err := reader.Read(ctx, editionID, editionHash)
94-
if err != nil {
95-
return err
96-
}
97-
98-
if err := writer.Write(edition); err != nil {
99-
return err
100-
}
101-
10297
edition.CheckedAt = time.Now().In(time.UTC)
10398

10499
mu.Lock()
@@ -126,3 +121,58 @@ func (c *Client) Run(ctx context.Context) error {
126121

127122
return nil
128123
}
124+
125+
// downloadEdition downloads the file with retries on HTTP2 INTERNAL_ERRORs.
126+
func (c *Client) downloadEdition(
127+
ctx context.Context,
128+
editionID string,
129+
r database.Reader,
130+
w database.Writer,
131+
) (*database.ReadResult, error) {
132+
editionHash, err := w.GetHash(editionID)
133+
if err != nil {
134+
return nil, err
135+
}
136+
137+
// RetryFor value of 0 means that no retries should be performed.
138+
// Max zero retries has to be set to achieve that
139+
// because the backoff never stops if MaxElapsedTime is zero.
140+
exp := backoff.NewExponentialBackOff()
141+
exp.MaxElapsedTime = c.config.RetryFor
142+
b := backoff.BackOff(exp)
143+
if exp.MaxElapsedTime == 0 {
144+
b = backoff.WithMaxRetries(exp, 0)
145+
}
146+
147+
var edition *database.ReadResult
148+
err = backoff.RetryNotify(
149+
func() error {
150+
edition, err = r.Read(ctx, editionID, editionHash)
151+
if err != nil {
152+
return backoff.Permanent(err)
153+
}
154+
155+
if err = w.Write(edition); err != nil {
156+
streamErr := http2.StreamError{}
157+
if errors.As(err, &streamErr) && streamErr.Code.String() == "INTERNAL_ERROR" {
158+
return err
159+
}
160+
161+
return backoff.Permanent(err)
162+
}
163+
164+
return nil
165+
},
166+
b,
167+
func(err error, d time.Duration) {
168+
if c.config.Verbose {
169+
log.Printf("Couldn't download %s, retrying in %v: %v", editionID, d, err)
170+
}
171+
},
172+
)
173+
if err != nil {
174+
return nil, err
175+
}
176+
177+
return edition, nil
178+
}

0 commit comments

Comments
 (0)