Skip to content

Commit

Permalink
feat: setup backoff retry strategy
Browse files Browse the repository at this point in the history
Signed-off-by: rare-magma <[email protected]>
  • Loading branch information
rare-magma committed Jan 19, 2025
1 parent 525f3d0 commit c1d5f5c
Showing 1 changed file with 54 additions and 9 deletions.
63 changes: 54 additions & 9 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"fmt"
"io"
"log"
"net"
"math"
"net/http"
"os"
"sync"
Expand All @@ -25,6 +25,52 @@ type Config struct {
GithubApiToken string `json:"GithubApiToken"`
}

type retryableTransport struct {
transport http.RoundTripper
TLSHandshakeTimeout time.Duration
ResponseHeaderTimeout time.Duration
}

const retryCount = 3

func shouldRetry(err error, resp *http.Response) bool {
if err != nil {
return true
}
switch resp.StatusCode {
case http.StatusInternalServerError, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout:
return true
default:
return false
}
}

func (t *retryableTransport) RoundTrip(req *http.Request) (*http.Response, error) {
var bodyBytes []byte
if req.Body != nil {
bodyBytes, _ = io.ReadAll(req.Body)
req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
}
resp, err := t.transport.RoundTrip(req)
retries := 0
for shouldRetry(err, resp) && retries < retryCount {
backoff := time.Duration(math.Pow(2, float64(retries))) * time.Second
time.Sleep(backoff)
if resp.Body != nil {
io.Copy(io.Discard, resp.Body)
resp.Body.Close()
}
if req.Body != nil {
req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
}
log.Printf("Previous request failed with %s", resp.Status)
log.Printf("Retry %d of request to: %s", retries+1, req.URL)
resp, err = t.transport.RoundTrip(req)
retries++
}
return resp, err
}

func main() {
confFilePath := "github_exporter.json"
confData, err := os.Open(confFilePath)
Expand Down Expand Up @@ -53,15 +99,14 @@ func main() {
log.Fatalln("GithubApiToken is required")
}

transport := &retryableTransport{
transport: &http.Transport{},
TLSHandshakeTimeout: 30 * time.Second,
ResponseHeaderTimeout: 30 * time.Second,
}
client := &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
}).DialContext,
TLSHandshakeTimeout: 30 * time.Second,
ResponseHeaderTimeout: 30 * time.Second,
},
Timeout: 30 * time.Second,
Transport: transport,
}
ghc := github.NewClient(client).WithAuthToken(config.GithubApiToken)
opts := &github.RepositoryListByAuthenticatedUserOptions{Type: "owner"}
Expand Down

0 comments on commit c1d5f5c

Please sign in to comment.