예제 #1
0
        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)));
            }
        }
예제 #2
0
        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));
            }
        }
예제 #3
0
 public override void Start(Action <ResolverResult> listener)
 {
     // Send addresses to listener once. They will never change.
     listener(ResolverResult.ForResult(_addresses, serviceConfig: null, serviceConfigStatus: null));
 }
예제 #4
0
        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);
            }
        }
예제 #5
0
 protected override void OnStarted()
 {
     // Send addresses to listener once. They will never change.
     Listener(ResolverResult.ForResult(_addresses, serviceConfig: null, serviceConfigStatus: null));
 }