Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,27 @@ public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context
return HealthCheckResult.Unhealthy(HealthCheckConstants.NoProviderFoundMessage);
}

HealthCheckResult worstResult = HealthCheckResult.Healthy();

foreach (IHealthCheck healthCheck in _healthChecks)
{
var result = await healthCheck.CheckHealthAsync(context, cancellationToken).ConfigureAwait(false);

// Keep track of the worst health status found
// HealthStatus enum is ordered: Unhealthy(0) < Degraded(1) < Healthy(2)
if (result.Status < worstResult.Status)
{
worstResult = result;
}

// If an Unhealthy status is found, short-circuit since that's the worst possible
if (result.Status == HealthStatus.Unhealthy)
{
return result;
}
}

return HealthCheckResult.Healthy();
return worstResult;
}

private void FindHealthChecks(IConfigurationRoot configurationRoot, List<IHealthCheck> healthChecks)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -574,15 +574,17 @@ public void ProcessPushNotification(PushNotification pushNotification, TimeSpan?

public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
HealthStatus failureStatus = context.Registration?.FailureStatus ?? HealthStatus.Unhealthy;

if (!_lastSuccessfulAttempt.HasValue)
{
return HealthCheckResult.Unhealthy(HealthCheckConstants.LoadNotCompletedMessage);
return new HealthCheckResult(status: failureStatus, description: HealthCheckConstants.LoadNotCompletedMessage);
}

if (_lastFailedAttempt.HasValue &&
_lastSuccessfulAttempt.Value < _lastFailedAttempt.Value)
{
return HealthCheckResult.Unhealthy(HealthCheckConstants.RefreshFailedMessage);
return new HealthCheckResult(status: failureStatus, description: HealthCheckConstants.RefreshFailedMessage);
}

return HealthCheckResult.Healthy();
Expand Down
49 changes: 49 additions & 0 deletions tests/Tests.AzureAppConfiguration/Unit/HealthCheckTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,5 +136,54 @@ public async Task HealthCheckTests_RegisterAzureAppConfigurationHealthCheck()
Assert.Contains(HealthCheckConstants.HealthCheckRegistrationName, result.Entries.Keys);
Assert.Equal(HealthStatus.Healthy, result.Entries[HealthCheckConstants.HealthCheckRegistrationName].Status);
}

[Fact]
public async Task HealthCheckTests_ShouldRespectHealthCheckRegistration()
{
IConfigurationRefresher refresher = null;
var mockResponse = new Mock<Response>();
var mockClient = new Mock<ConfigurationClient>(MockBehavior.Strict);

mockClient.SetupSequence(c => c.GetConfigurationSettingsAsync(It.IsAny<SettingSelector>(), It.IsAny<CancellationToken>()))
.Returns(new MockAsyncPageable(kvCollection))
.Throws(new RequestFailedException(503, "Request failed."));

var config = new ConfigurationBuilder()
.AddAzureAppConfiguration(options =>
{
options.ClientManager = TestHelpers.CreateMockedConfigurationClientManager(mockClient.Object);
options.MinBackoffDuration = TimeSpan.FromSeconds(2);
options.ConfigurationSettingPageIterator = new MockConfigurationSettingPageIterator();
options.ConfigureRefresh(refreshOptions =>
{
refreshOptions.RegisterAll()
.SetRefreshInterval(TimeSpan.FromSeconds(1));
});
refresher = options.GetRefresher();
})
.Build();

var services = new ServiceCollection();
services.AddSingleton<IConfiguration>(config);
services.AddLogging(); // add logging for health check service
services.AddHealthChecks()
.AddAzureAppConfiguration(
name: "TestName",
failureStatus: HealthStatus.Degraded);
var provider = services.BuildServiceProvider();
var healthCheckService = provider.GetRequiredService<HealthCheckService>();

var result = await healthCheckService.CheckHealthAsync();
Assert.Equal(HealthStatus.Healthy, result.Status);

// Wait for the refresh interval to expire
Thread.Sleep(2000);

await refresher.TryRefreshAsync();
result = await healthCheckService.CheckHealthAsync();
Assert.Equal(HealthStatus.Degraded, result.Status);
Assert.Contains("TestName", result.Entries.Keys);
Assert.Equal(HealthStatus.Degraded, result.Entries["TestName"].Status);
}
}
}
Loading