Skip to content
This repository was archived by the owner on Jan 15, 2024. It is now read-only.

Commit c957748

Browse files
Merge pull request #32 from flokli/support-num-retries
client.go: support NumRetries
2 parents c69abe9 + 143e77b commit c957748

File tree

1 file changed

+42
-10
lines changed

1 file changed

+42
-10
lines changed

client.go

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"os"
1313
"path"
1414
"strconv"
15+
"time"
1516

1617
"github.com/hashicorp/go-cleanhttp"
1718
)
@@ -33,6 +34,8 @@ type Config struct {
3334
Client *http.Client
3435
// OrgID provides an optional organization ID, ignored when using APIKey, BasicAuth defaults to last used org
3536
OrgID int64
37+
// NumRetries contains the number of attempted retries
38+
NumRetries int
3639
}
3740

3841
// New creates a new Grafana client.
@@ -59,18 +62,46 @@ func New(baseURL string, cfg Config) (*Client, error) {
5962
}
6063

6164
func (c *Client) request(method, requestPath string, query url.Values, body io.Reader, responseStruct interface{}) error {
62-
r, err := c.newRequest(method, requestPath, query, body)
63-
if err != nil {
64-
return err
65-
}
65+
var resp *http.Response
66+
var err error
67+
var bodyContents []byte
68+
69+
// retry logic
70+
for n := 0; n <= c.config.NumRetries; n++ {
71+
r, err := c.newRequest(method, requestPath, query, body)
72+
if err != nil {
73+
return err
74+
}
6675

67-
resp, err := c.client.Do(r)
68-
if err != nil {
69-
return err
70-
}
71-
defer resp.Body.Close()
76+
// Wait a bit if that's not the first request
77+
if n != 0 {
78+
time.Sleep(time.Second * 5)
79+
}
80+
81+
resp, err = c.client.Do(r)
7282

73-
bodyContents, err := ioutil.ReadAll(resp.Body)
83+
// If err is not nil, retry again
84+
// That's either caused by client policy, or failure to speak HTTP (such as network connectivity problem). A
85+
// non-2xx status code doesn't cause an error.
86+
if err != nil {
87+
continue
88+
}
89+
90+
defer resp.Body.Close()
91+
92+
// read the body (even on non-successful HTTP status codes), as that's what the unit tests expect
93+
bodyContents, err = ioutil.ReadAll(resp.Body)
94+
95+
// if there was an error reading the body, try again
96+
if err != nil {
97+
continue
98+
}
99+
100+
// Exit the loop if we have something final to return. This is anything < 500, if it's not a 429.
101+
if resp.StatusCode < http.StatusInternalServerError && resp.StatusCode != http.StatusTooManyRequests {
102+
break
103+
}
104+
}
74105
if err != nil {
75106
return err
76107
}
@@ -79,6 +110,7 @@ func (c *Client) request(method, requestPath string, query url.Values, body io.R
79110
log.Printf("response status %d with body %v", resp.StatusCode, string(bodyContents))
80111
}
81112

113+
// check status code.
82114
if resp.StatusCode >= 400 {
83115
return fmt.Errorf("status: %d, body: %v", resp.StatusCode, string(bodyContents))
84116
}

0 commit comments

Comments
 (0)