async Task <T> GetResponse <T>(YouTubeBaseServiceRequest <T> request) { void SetRequestKey() { if (AvailableKeys.Count == 0) { throw new InvalidOperationException("Ran out of quota for all available keys"); } request.Key = AvailableKeys.First().Key; } SetRequestKey(); return(await Policy // handle quote limits .Handle <GoogleApiException>(g => { var isQuotaError = g.HttpStatusCode == HttpStatusCode.Forbidden && g.Error.Errors.Any(e => e.Reason == "quotaExceeded"); if (!isQuotaError) { Log.Debug(g, "YtApi - return error not detected as quota: {Errors}", g.Error.Errors.Join(", ", e => e.Reason)); return false; } AvailableKeys.TryRemove(request.Key, out _); Log.Warning(g, "Quota exceeded, no longer using key {Key}", request.Key); SetRequestKey(); return true; }) .RetryForeverAsync() // wrap generic transient fault handling .WrapAsync(Policy .Handle <HttpRequestException>() .Or <GoogleApiException>(g => g.HttpStatusCode.IsTransientError()) .WaitAndRetryAsync(retryCount: 6, i => i.ExponentialBackoff(1.Seconds()))) .ExecuteAsync(request.ExecuteAsync)); }
async Task <T> GetResponse <T>(YouTubeBaseServiceRequest <T> request) { while (true) { try { if (AvailableKeys.Count == 0) { throw new InvalidOperationException("Ran out of quota for all available keys"); } request.Key = AvailableKeys.First(); // override key in case it has been changed by NextYtService() var response = await request.ExecuteAsync(); return(response); } catch (GoogleApiException ex) { if (ex.HttpStatusCode == HttpStatusCode.Forbidden) { AvailableKeys.Remove(request.Key); Log.Error(ex, "Quota exceeded, no longer using key {Key}", request.Key); } else { throw; } } } }
/// <summary> /// Logs a YouTube service response /// </summary> /// <typeparam name="T">The type of the request</typeparam> /// <param name="request">The request to log</param> /// <param name="response">The response to log</param> protected void LogResponse <T>(YouTubeBaseServiceRequest <T> request, string response) { if (Logger.Level == LogLevel.Debug) { Logger.Log(LogLevel.Debug, "Rest API Request Complete: " + request.RestPath + " - " + response); } }
/// <summary> /// Logs a YouTube service response /// </summary> /// <typeparam name="T">The type of the request</typeparam> /// <param name="request">The request to log</param> /// <param name="response">The response to log</param> protected void LogResponse <T>(YouTubeBaseServiceRequest <T> request, IDirectResponseSchema response) { if (Logger.Level == LogLevel.Debug) { Logger.Log(LogLevel.Debug, "Rest API Request Complete: " + request.RestPath + " - " + JSONSerializerHelper.SerializeToString(response)); } }
/// <summary> /// Logs a YouTube service request. /// </summary> /// <typeparam name="T">The type of the request</typeparam> /// <param name="request">The request to log</param> protected void LogRequest <T>(YouTubeBaseServiceRequest <T> request) { if (Logger.Level == LogLevel.Debug) { Logger.Log(LogLevel.Debug, "Rest API Request Sent: " + request.RestPath + " - " + JSONSerializerHelper.SerializeToString(request, propertiesToIgnore: requestPropertiesToIgnore)); } }
async Task <T> GetResponse <T>(YouTubeBaseServiceRequest <T> request) { void SetRequestKey() { if (AvailableKeys.Count == 0) { throw new InvalidOperationException("Ran out of quota for all available keys"); } request.Key = AvailableKeys.First().Key; } SetRequestKey(); return(await Policy // handle quote limits .Handle <GoogleApiException>(g => { if (g.HttpStatusCode != HttpStatusCode.Forbidden) { return false; } AvailableKeys.TryRemove(request.Key, out var value); Log.Error(g, "Quota exceeded, no longer using key {Key}", request.Key); SetRequestKey(); return true; }) .RetryForeverAsync() // wrap generic transient fault handling .WrapAsync(Policy .Handle <HttpRequestException>() .Or <GoogleApiException>(g => g.HttpStatusCode.IsTransient()) .WaitAndRetryAsync(3, i => i.ExponentialBackoff(1.Seconds()))) .ExecuteAsync(request.ExecuteAsync)); }