Skip to content

Commit c1d5f5c

Browse files
committed
feat: setup backoff retry strategy
Signed-off-by: rare-magma <[email protected]>
1 parent 525f3d0 commit c1d5f5c

File tree

1 file changed

+54
-9
lines changed

1 file changed

+54
-9
lines changed

main.go

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"fmt"
99
"io"
1010
"log"
11-
"net"
11+
"math"
1212
"net/http"
1313
"os"
1414
"sync"
@@ -25,6 +25,52 @@ type Config struct {
2525
GithubApiToken string `json:"GithubApiToken"`
2626
}
2727

28+
type retryableTransport struct {
29+
transport http.RoundTripper
30+
TLSHandshakeTimeout time.Duration
31+
ResponseHeaderTimeout time.Duration
32+
}
33+
34+
const retryCount = 3
35+
36+
func shouldRetry(err error, resp *http.Response) bool {
37+
if err != nil {
38+
return true
39+
}
40+
switch resp.StatusCode {
41+
case http.StatusInternalServerError, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout:
42+
return true
43+
default:
44+
return false
45+
}
46+
}
47+
48+
func (t *retryableTransport) RoundTrip(req *http.Request) (*http.Response, error) {
49+
var bodyBytes []byte
50+
if req.Body != nil {
51+
bodyBytes, _ = io.ReadAll(req.Body)
52+
req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
53+
}
54+
resp, err := t.transport.RoundTrip(req)
55+
retries := 0
56+
for shouldRetry(err, resp) && retries < retryCount {
57+
backoff := time.Duration(math.Pow(2, float64(retries))) * time.Second
58+
time.Sleep(backoff)
59+
if resp.Body != nil {
60+
io.Copy(io.Discard, resp.Body)
61+
resp.Body.Close()
62+
}
63+
if req.Body != nil {
64+
req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
65+
}
66+
log.Printf("Previous request failed with %s", resp.Status)
67+
log.Printf("Retry %d of request to: %s", retries+1, req.URL)
68+
resp, err = t.transport.RoundTrip(req)
69+
retries++
70+
}
71+
return resp, err
72+
}
73+
2874
func main() {
2975
confFilePath := "github_exporter.json"
3076
confData, err := os.Open(confFilePath)
@@ -53,15 +99,14 @@ func main() {
5399
log.Fatalln("GithubApiToken is required")
54100
}
55101

102+
transport := &retryableTransport{
103+
transport: &http.Transport{},
104+
TLSHandshakeTimeout: 30 * time.Second,
105+
ResponseHeaderTimeout: 30 * time.Second,
106+
}
56107
client := &http.Client{
57-
Timeout: 30 * time.Second,
58-
Transport: &http.Transport{
59-
DialContext: (&net.Dialer{
60-
Timeout: 30 * time.Second,
61-
}).DialContext,
62-
TLSHandshakeTimeout: 30 * time.Second,
63-
ResponseHeaderTimeout: 30 * time.Second,
64-
},
108+
Timeout: 30 * time.Second,
109+
Transport: transport,
65110
}
66111
ghc := github.NewClient(client).WithAuthToken(config.GithubApiToken)
67112
opts := &github.RepositoryListByAuthenticatedUserOptions{Type: "owner"}

0 commit comments

Comments
 (0)