@@ -11,15 +11,29 @@ import (
1111 "strings"
1212 "time"
1313
14- "github.com/save95 /xerror"
14+ "github.com/gomooth /xerror"
1515)
1616
1717type client struct {
18- config * Config
18+ config * Config
19+ httpClient * http.Client
1920}
2021
2122func NewClient (config * Config ) IClient {
22- return & client {config : config }
23+ timeout := config .Timeout
24+ if timeout <= 0 {
25+ timeout = 5 * time .Second
26+ }
27+ return & client {
28+ config : config ,
29+ httpClient : & http.Client {
30+ Timeout : timeout ,
31+ Transport : & http.Transport {
32+ MaxIdleConnsPerHost : 2 ,
33+ IdleConnTimeout : 90 * time .Second ,
34+ },
35+ },
36+ }
2337}
2438
2539func (c * client ) Put (ctx context.Context , name , data string ) (int64 , error ) {
@@ -168,30 +182,40 @@ func (c *client) SetSyncTime(ctx context.Context, name string, duration time.Dur
168182
169183func (c * client ) httpGet (ctx context.Context , values url.Values , parseHeaders []string ) (string , map [string ]string , error ) {
170184 furl := fmt .Sprintf ("http://%s/" , c .config .Addr )
171- req , err := http .NewRequestWithContext (ctx , http .MethodGet , furl , nil )
172- if nil != err {
173- return "" , nil , err
174- }
175185
176186 if len (c .config .Password ) > 0 {
177187 values .Set ("auth" , c .config .Password )
178188 }
179- req .URL .RawQuery = values .Encode ()
180189
181- httpClient := http .DefaultClient
182- if c .config .Timeout > 0 {
183- httpClient .Timeout = c .config .Timeout
184- } else {
185- httpClient .Timeout = 5 * time .Second
186- }
187- resp , err := httpClient .Do (req )
188- if nil != err {
189- return "" , nil , err
190+ var lastErr error
191+ maxAttempts := c .config .MaxRetries + 1
192+ for attempt := 0 ; attempt < maxAttempts ; attempt ++ {
193+ if attempt > 0 {
194+ if err := c .waitBackoff (ctx , attempt ); err != nil {
195+ return "" , nil , err
196+ }
197+ }
198+
199+ req , err := http .NewRequestWithContext (ctx , http .MethodGet , furl , nil )
200+ if err != nil {
201+ return "" , nil , err
202+ }
203+ req .URL .RawQuery = values .Encode ()
204+
205+ resp , err := c .httpClient .Do (req )
206+ if err != nil {
207+ lastErr = err
208+ continue
209+ }
210+
211+ return c .processResponse (resp , parseHeaders )
190212 }
191213
192- defer func () {
193- _ = resp .Body .Close ()
194- }()
214+ return "" , nil , xerror .Wrap (lastErr , "httpsqs request failed after retries" )
215+ }
216+
217+ func (c * client ) processResponse (resp * http.Response , parseHeaders []string ) (string , map [string ]string , error ) {
218+ defer resp .Body .Close ()
195219
196220 bodyBytes , err := io .ReadAll (resp .Body )
197221 if err != nil {
@@ -212,3 +236,16 @@ func (c *client) httpGet(ctx context.Context, values url.Values, parseHeaders []
212236 return body , headerResult , nil
213237 }
214238}
239+
240+ func (c * client ) waitBackoff (ctx context.Context , attempt int ) error {
241+ backoff := time .Duration (1 << uint (min (attempt - 1 , 24 ))) * 200 * time .Millisecond
242+ if backoff > 5 * time .Second {
243+ backoff = 5 * time .Second
244+ }
245+ select {
246+ case <- ctx .Done ():
247+ return ctx .Err ()
248+ case <- time .After (backoff ):
249+ return nil
250+ }
251+ }
0 commit comments