From 67cb3e42f1ee7c1eee7949c275fafbb2615794c6 Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Fri, 21 Sep 2018 07:42:52 -0500 Subject: [PATCH] TooManyRequests Handling (#282) * SpotifyHttpStatusCode A small supplementary enum for Spotify specific codes. Only contains TooManyRequests currently, but more can be added. * TooManyRequests Retry Handling Will now parse and wait the Spotify recommended wait time. Also has the option to not consume a retry attempt on this type of error * TryGetTooManyRequests refactored to GetTooManyRequests To keep the library consistent * Removed SpotifyHttpStatusCode --- SpotifyAPI.Web/Models/BasicModel.cs | 1 + SpotifyAPI.Web/Models/ResponseInfo.cs | 3 +- SpotifyAPI.Web/SpotifyWebAPI.cs | 48 ++++++++++++++++++++++++--- SpotifyAPI.Web/SpotifyWebClient.cs | 3 +- 4 files changed, 49 insertions(+), 6 deletions(-) diff --git a/SpotifyAPI.Web/Models/BasicModel.cs b/SpotifyAPI.Web/Models/BasicModel.cs index d6f54697..04727628 100644 --- a/SpotifyAPI.Web/Models/BasicModel.cs +++ b/SpotifyAPI.Web/Models/BasicModel.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json; +using SpotifyAPI.Web.Enums; using System; using System.Net; diff --git a/SpotifyAPI.Web/Models/ResponseInfo.cs b/SpotifyAPI.Web/Models/ResponseInfo.cs index 1a8a12c2..7a794387 100644 --- a/SpotifyAPI.Web/Models/ResponseInfo.cs +++ b/SpotifyAPI.Web/Models/ResponseInfo.cs @@ -1,4 +1,5 @@ -using System.Net; +using SpotifyAPI.Web.Enums; +using System.Net; namespace SpotifyAPI.Web.Models { diff --git a/SpotifyAPI.Web/SpotifyWebAPI.cs b/SpotifyAPI.Web/SpotifyWebAPI.cs index 2e628dc2..57f66acd 100644 --- a/SpotifyAPI.Web/SpotifyWebAPI.cs +++ b/SpotifyAPI.Web/SpotifyWebAPI.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using SpotifyAPI.Web.Enums; using SpotifyAPI.Web.Models; @@ -78,6 +78,11 @@ namespace SpotifyAPI.Web /// public int RetryTimes { get; set; } = 10; + /// + /// Whether a failure of type "Too Many Requests" should use up one of the allocated retry attempts. + /// + public bool TooManyRequestsConsumesARetry { get; set; } = false; + /// /// Error codes that will trigger auto-retry if is enabled. /// @@ -2445,6 +2450,26 @@ namespace SpotifyAPI.Web return response.Item2; } + /// + /// Retrieves whether request had a "TooManyRequests" error, and get the amount Spotify recommends waiting before another request. + /// + /// Info object to analyze. + /// Seconds to wait before making another request. -1 if no error. + /// AUTH NEEDED + private int GetTooManyRequests(ResponseInfo info) + { + // 429 is "TooManyRequests" value specified in Spotify API + if (429 != (int)info.StatusCode) + { + return -1; + } + if (!int.TryParse(info.Headers.Get("Retry-After"), out var secondsToWait)) + { + return -1; + } + return secondsToWait; + } + public async Task DownloadDataAsync(string url) where T : BasicModel { int triesLeft = RetryTimes + 1; @@ -2453,15 +2478,30 @@ namespace SpotifyAPI.Web Tuple response = null; do { - if (response != null) { await Task.Delay(RetryAfter).ConfigureAwait(false); } + if (response != null) + { + int msToWait = RetryAfter; + var secondsToWait = GetTooManyRequests(response.Item1); + if (secondsToWait > 0) + { + msToWait = secondsToWait * 1000; + } + await Task.Delay(msToWait).ConfigureAwait(false); + } response = await DownloadDataAltAsync(url).ConfigureAwait(false); response.Item2.AddResponseInfo(response.Item1); lastError = response.Item2.Error; - triesLeft -= 1; + if (TooManyRequestsConsumesARetry || GetTooManyRequests(response.Item1) == -1) + { + triesLeft -= 1; + } - } while (UseAutoRetry && triesLeft > 0 && lastError != null && RetryErrorCodes.Contains(lastError.Status)); + } while (UseAutoRetry + && triesLeft > 0 + && (GetTooManyRequests(response.Item1) != -1 + || (lastError != null && RetryErrorCodes.Contains(lastError.Status)))); return response.Item2; diff --git a/SpotifyAPI.Web/SpotifyWebClient.cs b/SpotifyAPI.Web/SpotifyWebClient.cs index b8c5c094..7c3a572b 100644 --- a/SpotifyAPI.Web/SpotifyWebClient.cs +++ b/SpotifyAPI.Web/SpotifyWebClient.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net; @@ -7,6 +7,7 @@ using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; using SpotifyAPI.Web.Models; +using SpotifyAPI.Web.Enums; namespace SpotifyAPI.Web {