2014-03-18 20:00:41 +04:00
|
|
|
package datasource
|
|
|
|
|
2014-04-23 02:36:07 +04:00
|
|
|
import (
|
|
|
|
"io/ioutil"
|
2014-05-15 09:20:40 +04:00
|
|
|
"log"
|
|
|
|
"math"
|
2014-04-23 02:36:07 +04:00
|
|
|
"net/http"
|
2014-05-15 09:20:40 +04:00
|
|
|
"time"
|
2014-04-23 02:36:07 +04:00
|
|
|
)
|
|
|
|
|
2014-05-15 21:04:37 +04:00
|
|
|
const maxTimeout = time.Second * 5
|
|
|
|
|
2014-03-18 20:00:41 +04:00
|
|
|
type Datasource interface {
|
|
|
|
Fetch() ([]byte, error)
|
2014-05-15 09:20:40 +04:00
|
|
|
Type() string
|
2014-03-18 20:00:41 +04:00
|
|
|
}
|
2014-04-23 02:36:07 +04:00
|
|
|
|
|
|
|
func fetchURL(url string) ([]byte, error) {
|
2014-05-15 09:20:40 +04:00
|
|
|
resp, err := getWithExponentialBackoff(url)
|
2014-04-23 02:36:07 +04:00
|
|
|
if err != nil {
|
|
|
|
return []byte{}, err
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
respBytes, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return respBytes, nil
|
|
|
|
}
|
2014-05-15 09:20:40 +04:00
|
|
|
|
|
|
|
// getWithExponentialBackoff issues a GET to the specified URL. If the
|
|
|
|
// response is a non-2xx or produces an error, retry the GET forever using
|
|
|
|
// an exponential backoff.
|
|
|
|
func getWithExponentialBackoff(url string) (*http.Response, error) {
|
|
|
|
var err error
|
|
|
|
var resp *http.Response
|
|
|
|
for i := 0; ; i++ {
|
|
|
|
resp, err = http.Get(url)
|
|
|
|
if err == nil && resp.StatusCode/100 == 2 {
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
duration := time.Millisecond * time.Duration((math.Pow(float64(2), float64(i)) * 100))
|
2014-05-15 21:04:37 +04:00
|
|
|
if duration > maxTimeout {
|
|
|
|
duration = maxTimeout
|
|
|
|
}
|
|
|
|
|
2014-05-15 09:20:40 +04:00
|
|
|
log.Printf("unable to fetch user-data from %s, try again in %s", url, duration)
|
|
|
|
time.Sleep(duration)
|
|
|
|
}
|
|
|
|
return resp, err
|
|
|
|
}
|