From 4e9f50b6b668b2a1cfa00c39ac9a3f7dea414e9f Mon Sep 17 00:00:00 2001 From: Philipp Wolfer Date: Wed, 15 Nov 2023 08:40:55 +0100 Subject: [PATCH] More resilient HTTP requests Fixed rate limit check for ListenBrainz and Funkwhale. Also retry always on server side errors. --- backends/funkwhale/client.go | 13 +++++++++++-- backends/listenbrainz/client.go | 14 +++++++++++--- backends/maloja/client.go | 13 ++++++------- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/backends/funkwhale/client.go b/backends/funkwhale/client.go index c178981..4080ac7 100644 --- a/backends/funkwhale/client.go +++ b/backends/funkwhale/client.go @@ -31,6 +31,7 @@ import ( ) const MaxItemsPerGet = 50 +const DefaultRateLimitWaitSeconds = 5 type Client struct { HttpClient *resty.Client @@ -48,12 +49,20 @@ func NewClient(serverUrl string, token string) Client { client.SetRetryCount(5) client.AddRetryCondition( func(r *resty.Response, err error) bool { - return r.StatusCode() == http.StatusTooManyRequests + code := r.StatusCode() + return code == http.StatusTooManyRequests || code >= http.StatusInternalServerError }, ) client.SetRetryMaxWaitTime(time.Duration(1 * time.Minute)) client.SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) { - retryAfter, err := strconv.Atoi(resp.Header().Get("X-RateLimit-Reset-In")) + var err error + var retryAfter int = DefaultRateLimitWaitSeconds + if resp.StatusCode() == http.StatusTooManyRequests { + retryAfter, err = strconv.Atoi(resp.Header().Get("Retry-After")) + if err != nil { + retryAfter = DefaultRateLimitWaitSeconds + } + } return time.Duration(retryAfter * int(time.Second)), err }) diff --git a/backends/listenbrainz/client.go b/backends/listenbrainz/client.go index 0e844c6..6fbab00 100644 --- a/backends/listenbrainz/client.go +++ b/backends/listenbrainz/client.go @@ -34,6 +34,7 @@ const listenBrainzBaseURL = "https://api.listenbrainz.org/1/" const DefaultItemsPerGet = 25 const MaxItemsPerGet = 1000 +const DefaultRateLimitWaitSeconds = 5 type Client struct { HttpClient *resty.Client @@ -46,18 +47,25 @@ func NewClient(token string) Client { client.SetAuthScheme("Token") client.SetAuthToken(token) client.SetHeader("Accept", "application/json") - client.SetHeader("Content-Type", "application/json") // Handle rate limiting (see https://listenbrainz.readthedocs.io/en/latest/users/api/index.html#rate-limiting) client.SetRetryCount(5) client.AddRetryCondition( func(r *resty.Response, err error) bool { - return r.StatusCode() == http.StatusTooManyRequests + code := r.StatusCode() + return code == http.StatusTooManyRequests || code >= http.StatusInternalServerError }, ) client.SetRetryMaxWaitTime(time.Duration(1 * time.Minute)) client.SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) { - retryAfter, err := strconv.Atoi(resp.Header().Get("Retry-After")) + var err error + var retryAfter int = DefaultRateLimitWaitSeconds + if resp.StatusCode() == http.StatusTooManyRequests { + retryAfter, err = strconv.Atoi(resp.Header().Get("X-RateLimit-Reset-In")) + if err != nil { + retryAfter = DefaultRateLimitWaitSeconds + } + } return time.Duration(retryAfter * int(time.Second)), err }) diff --git a/backends/maloja/client.go b/backends/maloja/client.go index 0c502ff..893f5f8 100644 --- a/backends/maloja/client.go +++ b/backends/maloja/client.go @@ -34,15 +34,14 @@ type Client struct { } func NewClient(serverUrl string, token string) Client { - resty := resty.New() - resty.SetBaseURL(serverUrl) - resty.SetHeader("Accept", "application/json") - client := Client{ - HttpClient: resty, + client := resty.New() + client.SetBaseURL(serverUrl) + client.SetHeader("Accept", "application/json") + client.SetRetryCount(5) + return Client{ + HttpClient: client, token: token, } - - return client } func (c Client) GetScrobbles(page int, perPage int) (result GetScrobblesResult, err error) {