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"); }