@@ -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
6164func (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