/// <summary>Dispatch an HTTP request.</summary> /// <param name="request">The response message to validate.</param> /// <param name="dispatcher">A method which executes the request.</param> /// <returns>The final HTTP response.</returns> public async Task <HttpResponseMessage> ExecuteAsync(IRequest request, Func <IRequest, Task <HttpResponseMessage> > dispatcher) { int attempt = 0; while (true) { // dispatch request attempt++; var response = await DispatchRequest(request, dispatcher).ConfigureAwait(false); // check if the token needs to be refreshed if (response.StatusCode == HttpStatusCode.Unauthorized) { var responseContent = await response.Content.ReadAsStringAsync(null).ConfigureAwait(false); var jObject = JObject.Parse(responseContent); var message = jObject.GetPropertyValue("message", string.Empty); if (message.StartsWith("access token is expired", StringComparison.OrdinalIgnoreCase)) { var refreshedToken = _tokenHandler.RefreshTokenIfNecessary(true); request = request.WithBearerAuthentication(refreshedToken); response = await DispatchRequest(request, dispatcher); } } // find the applicable retry configuration, if any IRetryConfig retryConfig = RetryConfig.None(); bool shouldRetry = false; foreach (var config in _retryConfigs) { if (config.ShouldRetry(response)) { retryConfig = config; shouldRetry = true; break; } } // exit if there is no need to retry the request if (!shouldRetry) { return(response); } int maxAttempt = 1 + retryConfig?.MaxRetries ?? 0; // throw an exception if we have reached the maximum number of retries if (attempt > maxAttempt) { throw new ApiException(new Response(response, request.Formatters), $"The HTTP request failed, and the retry coordinator gave up after the maximum {maxAttempt} retries"); } // set up retry TimeSpan delay = retryConfig.GetDelay(attempt, response); if (delay.TotalMilliseconds > 0) { await Task.Delay(delay).ConfigureAwait(false); } } }
/// <summary> /// Initializes a new instance of the <see cref="ZoomRetryCoordinator" /> class. /// </summary> /// <param name="config">The retry configuration.</param> /// <param name="tokenHandler">The handler that takes care of renewing expired tokens.</param> public ZoomRetryCoordinator(IRetryConfig config, ITokenHandler tokenHandler) : this(tokenHandler) { if (config != null) { _retryConfigs.Add(config); } }
/// <summary>Construct an instance.</summary> /// <param name="config">The retry configuration.</param> public RetryCoordinator(IRetryConfig config) { this.Config = config ?? RetryConfig.None(); }
/// <summary> /// Initializes a new instance of the <see cref="ZoomRetryCoordinator" /> class. /// </summary> /// <param name="config">The retry configuration.</param> /// <param name="tokenHandler">The handler that takes care of renewing expired tokens.</param> public ZoomRetryCoordinator(IRetryConfig config, ITokenHandler tokenHandler) : this(tokenHandler) { _defaultRetryCoordinator = new RetryCoordinator(config); }
/// <summary>Construct an instance.</summary> /// <param name="config">The retry configuration.</param> public RetryCoordinator(IRetryConfig config) { this.Config = config; }
/// <summary>Set the request coordinator for this request</summary> /// <param name="request">The request.</param> /// <param name="config">The retry config (or null to use the default behaviour).</param> public static IRequest WithRequestCoordinator(this IRequest request, IRetryConfig config) { return(request.WithRequestCoordinator(new RetryCoordinator(config))); }
/// <summary>Set the default request coordinator.</summary> /// <param name="client">The client.</param> /// <param name="config">The retry configuration (or null for the default coordinator).</param> public static IClient SetRequestCoordinator(this IClient client, IRetryConfig config) { return(client.SetRequestCoordinator(new RetryCoordinator(config))); }