proxy client with retry
This commit is contained in:
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user