Exemple #1
0
        internal static async Task <TResponse> Retry <TRequest, TResponse>(
            Func <TRequest, CallSettings, Task <TResponse> > fn,
            TRequest request, CallSettings callSettings, IClock clock, IScheduler scheduler)
        {
            RetrySettings retrySettings = callSettings.Retry;

            if (retrySettings == null)
            {
                return(await fn(request, callSettings).ConfigureAwait(false));
            }
            DateTime?overallDeadline = callSettings.Expiration.CalculateDeadline(clock);

            // Every attempt should use the same deadline, calculated from the start of the call.
            if (callSettings.Expiration?.Type == ExpirationType.Timeout)
            {
                callSettings = callSettings.WithDeadline(overallDeadline.Value);
            }
            // Remove retry from the call settings we pass into the function, so that the settings
            // can be used even for a streaming call.
            callSettings = callSettings.WithRetry(null);

            foreach (var attempt in RetryAttempt.CreateRetrySequence(retrySettings, scheduler, overallDeadline, clock))
            {
                try
                {
                    return(await fn(request, callSettings).ConfigureAwait(false));
                }
                catch (RpcException e) when(attempt.ShouldRetry(e))
                {
                    await attempt.BackoffAsync(callSettings.CancellationToken.GetValueOrDefault()).ConfigureAwait(false);
                }
            }
            throw new InvalidOperationException("Bug in GAX retry handling: finished sequence of attempts");
        }
Exemple #2
0
        internal static async Task RetryOperationUntilCompleted(
            Func <CallSettings, Task <bool> > fn,
            IClock clock,
            IScheduler scheduler,
            CallSettings callSettings,
            RetrySettings retrySettings)
        {
            DateTime?overallDeadline = callSettings.Expiration.CalculateDeadline(clock);

            // Every attempt should use the same deadline, calculated from the start of the call.
            if (callSettings.Expiration?.Type == ExpirationType.Timeout)
            {
                callSettings = callSettings.WithDeadline(overallDeadline.Value);
            }

            var deadlineException = new RpcException(new Status(StatusCode.DeadlineExceeded, "Deadline Exceeded"));

            foreach (var attempt in RetryAttempt.CreateRetrySequence(retrySettings, scheduler, overallDeadline, clock))
            {
                try
                {
                    bool isResponseOk = await fn(callSettings).ConfigureAwait(false);

                    if (isResponseOk)
                    {
                        return;
                    }
                    if (!attempt.ShouldRetry(deadlineException))
                    {
                        throw deadlineException;
                    }
                }
                catch (RpcException e) when(attempt.ShouldRetry(e))
                {
                    // We back off below...
                }
                await attempt.BackoffAsync(callSettings.CancellationToken.GetValueOrDefault()).ConfigureAwait(false);
            }
            throw new InvalidOperationException("Bug in GAX retry handling: finished sequence of attempts");
        }