protected override async Task ResolveAsync(CancellationToken cancellationToken) { try { var elapsedTimeSinceLastRefresh = SystemClock.UtcNow - _lastResolveStart; if (elapsedTimeSinceLastRefresh < MinimumDnsResolutionRate) { var delay = MinimumDnsResolutionRate - elapsedTimeSinceLastRefresh; DnsResolverLog.StartingRateLimitDelay(_logger, delay, MinimumDnsResolutionRate); await Task.Delay(delay, cancellationToken).ConfigureAwait(false); } var lastResolveStart = SystemClock.UtcNow; if (string.IsNullOrEmpty(_dnsAddress)) { throw new InvalidOperationException($"Resolver address '{_originalAddress}' is not valid. Please use dns:/// for DNS provider."); } DnsResolverLog.StartingDnsQuery(_logger, _dnsAddress); var addresses = #if NET6_0_OR_GREATER await Dns.GetHostAddressesAsync(_dnsAddress, cancellationToken).ConfigureAwait(false); #else await Dns.GetHostAddressesAsync(_dnsAddress).ConfigureAwait(false); #endif DnsResolverLog.ReceivedDnsResults(_logger, addresses.Length, _dnsAddress, addresses); var endpoints = addresses.Select(a => new BalancerAddress(a.ToString(), _port)).ToArray(); var resolverResult = ResolverResult.ForResult(endpoints); Listener(resolverResult); // Only update last resolve start if successful. Backoff will handle limiting resolves on failure. _lastResolveStart = lastResolveStart; } catch (Exception ex) { var message = $"Error getting DNS hosts for address '{_dnsAddress}'."; DnsResolverLog.ErrorQueryingDns(_logger, _dnsAddress, ex); Listener(ResolverResult.ForFailure(GrpcProtocolHelpers.CreateStatusFromException(message, ex, StatusCode.Unavailable))); } }
private async Task ResolveNowAsync(CancellationToken cancellationToken) { try { await ResolveAsync(cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested) { // Ignore cancellation. } catch (Exception ex) { Log.ResolverRefreshError(_logger, ex); var status = GrpcProtocolHelpers.CreateStatusFromException("Error refreshing resolver.", ex); Listener(ResolverResult.ForFailure(status)); } }
private async Task ResolveNowAsync(CancellationToken cancellationToken) { // Reset resolve success to false. Will be set to true when an OK result is sent to listener. _resolveSuccessful = false; try { var backoffPolicy = _backoffPolicyFactory?.Create(); for (var attempt = 0; ; attempt++) { try { await ResolveAsync(cancellationToken).ConfigureAwait(false); // ResolveAsync may report a failure but not throw. Check to see whether an OK result // has been reported. If not then start retry loop. if (_resolveSuccessful) { return; } } catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested) { // Ignore cancellation. break; } catch (Exception ex) { Log.ResolveError(_logger, GetType(), ex); var status = GrpcProtocolHelpers.CreateStatusFromException("Error refreshing resolver.", ex); Listener(ResolverResult.ForFailure(status)); } // No backoff policy specified. Exit immediately. if (backoffPolicy == null) { break; } var backoffTicks = backoffPolicy.NextBackoff().Ticks; // Task.Delay supports up to Int32.MaxValue milliseconds. // Note that even if the maximum backoff is configured to this maximum, the jitter could push it over the limit. // Force an upper bound here to ensure an unsupported backoff is never used. backoffTicks = Math.Min(backoffTicks, TimeSpan.TicksPerMillisecond * int.MaxValue); var backkoff = TimeSpan.FromTicks(backoffTicks); Log.StartingResolveBackoff(_logger, GetType(), backkoff); await Task.Delay(backkoff, cancellationToken).ConfigureAwait(false); } } catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested) { // Ignore cancellation. } catch (Exception ex) { Log.ErrorRetryingResolve(_logger, GetType(), ex); } }