Example #1
0
        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));
        }
Example #2
0
        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); }
        }
Example #3
0
        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());