proxy client with retry

This commit is contained in:
Umputun
2018-06-08 03:12:22 -05:00
parent 94734ed4cb
commit 424e0cf73c
4 changed files with 50 additions and 6 deletions
+18 -2
View File
@@ -40,10 +40,16 @@ func (p *Avatar) Put(u store.User) (avatarURL string, err error) {
// load avatar from remote location
client := http.Client{Timeout: 10 * time.Second}
resp, err := client.Get(u.Picture)
var resp *http.Response
err = retry(5, time.Second, func() error {
var e error
resp, e = client.Get(u.Picture)
return e
})
if err != nil {
return "", errors.Wrapf(err, "failed to get avatar for user %s from %s", u.ID, u.Picture)
return "", errors.Wrap(err, "failed to fetch avatar from the orig")
}
defer func() {
if e := resp.Body.Close(); e != nil {
log.Printf("[WARN] can't close response body, %s", e)
@@ -106,3 +112,13 @@ func (p *Avatar) Routes(middlewares ...func(http.Handler) http.Handler) (string,
return p.RoutePath, router
}
func retry(retries int, delay time.Duration, fn func() error) (err error) {
for i := 0; i < retries; i++ {
if err = fn(); err == nil {
return nil
}
time.Sleep(delay)
}
return errors.Wrap(err, "retry failed")
}
+3 -3
View File
@@ -17,8 +17,8 @@ import (
// AvatarStore defines interface to store and serve avatars
type AvatarStore interface {
Put(userID string, reader io.Reader) (avatarURL string, err error)
Get(userID string) (reader io.ReadCloser, size int, err error)
Put(userID string, reader io.Reader) (avatar string, err error)
Get(avatar string) (reader io.ReadCloser, size int, err error)
}
// FSAvatarStore implements AvatarStore for local file system
@@ -33,7 +33,7 @@ func NewFSAvatarStore(storePath string) *FSAvatarStore {
return &FSAvatarStore{storePath: storePath}
}
// Put avatar for userID to file and return avatar name
// Put avatar for userID to file and return avatar's file name (base), like 12345678.image
func (fs *FSAvatarStore) Put(userID string, reader io.Reader) (avatar string, err error) {
id := store.EncodeID(userID)
+22
View File
@@ -2,6 +2,7 @@ package proxy
import (
"bytes"
"errors"
"fmt"
"io"
"log"
@@ -9,6 +10,7 @@ import (
"net/http/httptest"
"os"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -118,3 +120,23 @@ func TestAvatar_Routes(t *testing.T) {
assert.Equal(t, int64(21), sz)
assert.Equal(t, "some picture bin data", bb.String())
}
func TestAvatar_Retry(t *testing.T) {
i := 0
err := retry(5, time.Millisecond, func() error {
if i == 3 {
return nil
}
i++
return errors.New("err")
})
assert.Nil(t, err)
assert.Equal(t, 3, i)
st := time.Now()
err = retry(5, time.Millisecond, func() error {
return errors.New("err")
})
assert.NotNil(t, err)
assert.True(t, time.Since(st) >= time.Microsecond*5)
}
+7 -1
View File
@@ -48,8 +48,14 @@ func (p Image) Routes() chi.Router {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't decode image url")
return
}
client := http.Client{Timeout: 30 * time.Second}
resp, err := client.Get(string(src))
var resp *http.Response
err = retry(5, time.Second, func() error {
var e error
resp, e = client.Get(string(src))
return e
})
if err != nil {
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get image "+string(src))
return