Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve diagnostics for IDestinationResolver exceptions #2241

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/ReverseProxy/Management/ProxyConfigManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,17 @@ private async ValueTask<IProxyConfig> LoadConfigAsyncCore(IProxyConfig config, C
{
foreach (var (i, task) in resolverTasks)
{
var resolvedDestinations = await task;
ResolvedDestinationCollection resolvedDestinations;
try
{
resolvedDestinations = await task;
}
catch (Exception exception)
{
var cluster = clusters[i];
throw new InvalidOperationException($"Error resolving destinations for cluster {cluster.ClusterId}", exception);
}

clusters[i] = clusters[i] with { Destinations = resolvedDestinations.Destinations };
if (resolvedDestinations.ChangeToken is { } token)
{
Expand Down
18 changes: 14 additions & 4 deletions src/ReverseProxy/ServiceDiscovery/DnsDestinationResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,21 @@ public async ValueTask<ResolvedDestinationCollection> ResolveDestinationsAsync(I
{
var originalUri = new Uri(originalConfig.Address);
var originalHost = originalConfig.Host is { Length: > 0 } host ? host : originalUri.Authority;
var addresses = options.AddressFamily switch
var hostName = originalUri.DnsSafeHost;
IPAddress[] addresses;
try
{
{ } addressFamily => await Dns.GetHostAddressesAsync(originalUri.DnsSafeHost, addressFamily, cancellationToken).ConfigureAwait(false),
null => await Dns.GetHostAddressesAsync(originalUri.DnsSafeHost, cancellationToken).ConfigureAwait(false)
};
addresses = options.AddressFamily switch
{
{ } addressFamily => await Dns.GetHostAddressesAsync(hostName, addressFamily, cancellationToken).ConfigureAwait(false),
null => await Dns.GetHostAddressesAsync(hostName, cancellationToken).ConfigureAwait(false)
};
}
catch (Exception exception)
{
throw new InvalidOperationException($"Failed to resolve host '{hostName}'. See {nameof(Exception.InnerException)} for details.", exception);
}

var results = new List<(string Name, DestinationConfig Config)>(addresses.Length);
var uriBuilder = new UriBuilder(originalUri);
var healthUri = originalConfig.Health is { Length: > 0 } health ? new Uri(health) : null;
Expand Down
12 changes: 8 additions & 4 deletions test/ReverseProxy.Tests/Management/ProxyConfigManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1392,8 +1392,10 @@ public async Task LoadAsync_DestinationResolver_Initial_ThrowsAsync()
var ioEx = await Assert.ThrowsAsync<InvalidOperationException>(() => configManager.InitialLoadAsync());
Assert.Equal("Unable to load or apply the proxy configuration.", ioEx.Message);

var innerExc = Assert.IsType<InvalidOperationException>(ioEx.InnerException);
Assert.Equal("Throwing!", innerExc.Message);
var innerExc1 = Assert.IsType<InvalidOperationException>(ioEx.InnerException);
Assert.Equal("Error resolving destinations for cluster cluster1", innerExc1.Message);
var innerExc2 = Assert.IsType<InvalidOperationException>(innerExc1.InnerException);
Assert.Equal("Throwing!", innerExc2.Message);
}

[Fact]
Expand Down Expand Up @@ -1640,7 +1642,9 @@ public async Task LoadAsync_DestinationResolver_Reload_ThrowsAsync()

// Read the failure event
var configLoadException = Assert.IsType<TestConfigChangeListener.ConfigurationLoadingFailedEvent>(await configListener.Events.Reader.ReadAsync());
var ex = configLoadException.Exception;
Assert.Equal("Throwing!", ex.Message);
var innerExc1 = Assert.IsType<InvalidOperationException>(configLoadException.Exception);
Assert.Equal("Error resolving destinations for cluster cluster1", innerExc1.Message);
var innerExc2 = Assert.IsType<InvalidOperationException>(innerExc1.InnerException);
Assert.Equal("Throwing!", innerExc2.Message);
}
}