public static IObservable <TResponse[]> List <TResponse, TMaxResult>(this IClientServiceRequest <TResponse> request, TMaxResult maxResults, ICloudOfficeToken cloudOfficeToken = null, Action <ICloudOfficeToken> saveToken = null, Func <GoogleApiException, bool> repeat = null) { request.SetPropertyValue("MaxResults", maxResults); repeat ??= (exception => exception.HttpStatusCode == HttpStatusCode.Gone); if (cloudOfficeToken != null) { request.SetPropertyValue("SyncToken", cloudOfficeToken.Token); } var allEvents = Observable.FromAsync(() => request.ExecuteAsync()) .Catch <TResponse, GoogleApiException>(e => { if (cloudOfficeToken != null) { cloudOfficeToken.Token = null; } return(repeat(e) ? request.List(maxResults, cloudOfficeToken, saveToken, repeat).SelectMany(responses => responses) : Observable.Throw <TResponse>(e)); }) .Do(_ => request.SetPropertyValue("PageToken", _.GetPropertyValue("NextPageToken"))) .Repeat().TakeUntil(_ => request.GetPropertyValue("PageToken") == null) .Finally(() => saveToken?.Invoke(cloudOfficeToken)) .Publish().RefCount(); if (cloudOfficeToken != null) { allEvents = allEvents.Where(_ => _.GetPropertyValue("NextSyncToken") != null).LastOrDefaultAsync().Do(_ => { if (_ != null) { cloudOfficeToken.Token = $"{_.GetPropertyValue("NextSyncToken")}"; } }).IgnoreElements().Merge(allEvents); } return(allEvents.BufferUntilCompleted().Select(responses => responses)); }
private static async Task <TResponse> SafeExecuteAsync <TResponse>(IClientServiceRequest <TResponse> request, int attemptOrderNumber) { // Attempt to execute provided request. try { return(await request.ExecuteAsync()); } // On request operation canceled catch (OperationCanceledException ex) { // Increase attempt order number by one. attemptOrderNumber++; // Validate whether request reattempt limit hasn't been exceeded if (RequestsExecutor._cancellationErrorAttemptsLimit < attemptOrderNumber) { // ... and throw appropriate exception if has. attempt throw new RequestExecutionUnexpectedException(request, ex); } // Await appropriate cooldown period. await Task.Delay(RequestsExecutor._cancellationErrorCooldown); // Reattempt. return(await RequestsExecutor.SafeExecuteAsync(request, attemptOrderNumber)); } // On google internal error encounter, retry catch (Google.GoogleApiException ex) when(ex.Message.Contains("Internal error encountered. [500]")) { // Increase attempt order number by one. attemptOrderNumber++; // Validate whether request reattempt limit hasn't been exceeded if (RequestsExecutor._internalErrorAttemptsLimit < attemptOrderNumber) { // ... and throw appropriate exception if has. attempt throw new RequestExecutionUnexpectedException(request, ex); } // Await appropriate cooldown period. await Task.Delay(RequestsExecutor._internalErrorCooldown); // Reattempt. return(await RequestsExecutor.SafeExecuteAsync <TResponse>(request, attemptOrderNumber)); } // On used all available requests quota catch (Google.GoogleApiException ex) when(ex.Message.Contains("Quota exceeded for quota group")) { // Set session request limiter state to indicate no available google requests quota at this time. SessionRequestsLimiter.Instance.ClearAvailableQuota(); // Reattempt. return(await RequestsExecutor.SafeExecuteAsync <TResponse>(request, attemptOrderNumber)); } // On any other unexpected database error catch (Google.GoogleApiException ex) { throw new RequestExecutionUnexpectedException(request, ex); } }
public static async Task ExecuteAndAwaitOperationAsync( this IClientServiceRequest <Google.Apis.Compute.v1.Data.Operation> request, string projectId, CancellationToken token) { var operation = await request.ExecuteAsync(token).ConfigureAwait(false); while (true) { token.ThrowIfCancellationRequested(); if (operation.Status == DoneStatus) { if (operation.HttpErrorStatusCode >= 400) { // Operation failed. Translate error details into an // exception. var errors = operation.Error != null && operation.Error.Errors != null ? operation.Error.Errors .Select(e => new SingleError() { Message = e.Message, Location = e.Location }) .ToList() : NoErrors; TraceSources.Common.TraceWarning("Operation failed: {0}", operation.HttpErrorMessage); throw new GoogleApiException( "ComputeEngine", operation.HttpErrorMessage) { Error = new RequestError() { Code = operation.HttpErrorStatusCode ?? 0, Message = operation.HttpErrorMessage, Errors = errors } }; } else { TraceSources.Common.TraceVerbose("Operation completed"); return; } } await Task.Delay(200).ConfigureAwait(false); var pollRequest = new ZoneOperationsResource(request.Service).Get( projectId, ShortIdFromUrl(operation.Zone), operation.Name); operation = await pollRequest .ExecuteAsync(token) .ConfigureAwait(false); } }
public static async Task <TResponse> ExecuteWithRetryAsync <TResponse>(this IClientServiceRequest <TResponse> request) => await ExecuteWithRetryAsync(() => request.ExecuteAsync());