Merge pull request #522 from dotnet-maestro-bot/merge/release/2.2-to-master

[automated] Merge branch 'release/2.2' => 'master'
This commit is contained in:
Ryan Nowak 2018-10-31 13:26:02 -07:00 committed by GitHub
commit c9a53b9067
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 158 additions and 155 deletions

View File

@ -51,11 +51,11 @@ namespace HealthChecksSample
}
catch (DbException ex)
{
return HealthCheckResult.Failed(exception: ex);
return new HealthCheckResult(status: context.Registration.FailureStatus, exception: ex);
}
}
return HealthCheckResult.Passed();
return HealthCheckResult.Healthy();
}
}
}

View File

@ -65,13 +65,15 @@ namespace HealthChecksSample
{ "Gen2Collections", GC.CollectionCount(2) },
};
// Report failure if the allocated memory is >= the threshold. Negated because true == success
var result = !(allocated >= options.Threshold);
// Report failure if the allocated memory is >= the threshold.
//
// Using context.Registration.FailureStatus means that the application developer can configure
// how they want failures to appear.
var result = allocated >= options.Threshold ? context.Registration.FailureStatus : HealthStatus.Healthy;
return Task.FromResult(new HealthCheckResult(
result,
description: "reports degraded status if allocated bytes >= 1gb",
exception: null,
data: data));
}
}

View File

@ -21,10 +21,12 @@ namespace HealthChecksSample
{
if (_task.IsCompleted)
{
return Task.FromResult(HealthCheckResult.Passed("Dependency is ready"));
return Task.FromResult(HealthCheckResult.Healthy("Dependency is ready"));
}
return Task.FromResult(HealthCheckResult.Failed("Dependency is still initializing"));
return Task.FromResult(new HealthCheckResult(
status: context.Registration.FailureStatus,
description: "Dependency is still initializing"));
}
}
}

View File

@ -33,9 +33,6 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
{ HealthStatus.Healthy, StatusCodes.Status200OK },
{ HealthStatus.Degraded, StatusCodes.Status200OK },
{ HealthStatus.Unhealthy, StatusCodes.Status503ServiceUnavailable },
// This means that a health check failed, so 500 is appropriate. This is an error.
{ HealthStatus.Failed, StatusCodes.Status500InternalServerError },
};
/// <summary>

View File

@ -14,16 +14,16 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
private static readonly IReadOnlyDictionary<string, object> _emptyReadOnlyDictionary = new Dictionary<string, object>();
/// <summary>
/// Creates a new <see cref="HealthCheckResult"/> with the specified values for <paramref name="result"/>, <paramref name="exception"/>,
/// <paramref name="description"/>, and <paramref name="data"/>.
/// Creates a new <see cref="HealthCheckResult"/> with the specified values for <paramref name="status"/>,
/// <paramref name="exception"/>, <paramref name="description"/>, and <paramref name="data"/>.
/// </summary>
/// <param name="result">A value indicating the pass/fail status of the component that was checked.</param>
/// <param name="status">A value indicating the status of the component that was checked.</param>
/// <param name="description">A human-readable description of the status of the component that was checked.</param>
/// <param name="exception">An <see cref="Exception"/> representing the exception that was thrown when checking for status (if any).</param>
/// <param name="data">Additional key-value pairs describing the health of the component.</param>
public HealthCheckResult(bool result, string description, Exception exception, IReadOnlyDictionary<string, object> data)
public HealthCheckResult(HealthStatus status, string description = null, Exception exception = null, IReadOnlyDictionary<string, object> data = null)
{
Result = result;
Status = status;
Description = description;
Exception = exception;
Data = data ?? _emptyReadOnlyDictionary;
@ -45,33 +45,44 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
public Exception Exception { get; }
/// <summary>
/// Gets a value indicating the pass/fail status of the component that was checked. If <c>true</c>, then the component
/// is considered to have passed health validation. A <c>false</c> value will be mapped to the configured
/// <see cref="HealthStatus"/> by the health check system.
/// Gets a value indicating the status of the component that was checked.
/// </summary>
public bool Result { get; }
public HealthStatus Status { get; }
/// <summary>
/// Creates a <see cref="HealthCheckResult"/> representing a passing component.
/// Creates a <see cref="HealthCheckResult"/> representing a healthy component.
/// </summary>
/// <returns>A <see cref="HealthCheckResult"/> representing a passing component.</returns>
/// <param name="description">A human-readable description of the status of the component that was checked. Optional.</param>
/// <param name="data">Additional key-value pairs describing the health of the component. Optional.</param>
public static HealthCheckResult Passed(string description = null, IReadOnlyDictionary<string, object> data = null)
/// <returns>A <see cref="HealthCheckResult"/> representing a healthy component.</returns>
public static HealthCheckResult Healthy(string description = null, IReadOnlyDictionary<string, object> data = null)
{
return new HealthCheckResult(result: true, description, exception: null, data);
return new HealthCheckResult(status: HealthStatus.Healthy, description, exception: null, data);
}
/// <summary>
/// Creates a <see cref="HealthCheckResult"/> representing an failing component.
/// Creates a <see cref="HealthCheckResult"/> representing a degraded component.
/// </summary>
/// <param name="description">A human-readable description of the status of the component that was checked. Optional.</param>
/// <param name="exception">An <see cref="Exception"/> representing the exception that was thrown when checking for status. Optional.</param>
/// <param name="data">Additional key-value pairs describing the health of the component. Optional.</param>
/// <returns>A <see cref="HealthCheckResult"/> representing an failing component.</returns>
public static HealthCheckResult Failed(string description = null, Exception exception = null, IReadOnlyDictionary<string, object> data = null)
/// <returns>A <see cref="HealthCheckResult"/> representing a degraged component.</returns>
public static HealthCheckResult Degraded(string description = null, Exception exception = null, IReadOnlyDictionary<string, object> data = null)
{
return new HealthCheckResult(result: false, description, exception, data);
return new HealthCheckResult(status: HealthStatus.Degraded, description, exception: null, data);
}
/// <summary>
/// Creates a <see cref="HealthCheckResult"/> representing an unhealthy component.
/// </summary>
/// <param name="description">A human-readable description of the status of the component that was checked. Optional.</param>
/// <param name="exception">An <see cref="Exception"/> representing the exception that was thrown when checking for status. Optional.</param>
/// <param name="data">Additional key-value pairs describing the health of the component. Optional.</param>
/// <returns>A <see cref="HealthCheckResult"/> representing an unhealthy component.</returns>
public static HealthCheckResult Unhealthy(string description = null, Exception exception = null, IReadOnlyDictionary<string, object> data = null)
{
return new HealthCheckResult(status: HealthStatus.Unhealthy, description, exception, data);
}
}
}

View File

@ -54,7 +54,7 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
currentValue = entry.Status;
}
if (currentValue == HealthStatus.Failed)
if (currentValue == HealthStatus.Unhealthy)
{
// Game over, man! Game over!
// (We hit the worst possible status, so there's no need to keep iterating)

View File

@ -52,8 +52,7 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
public Exception Exception { get; }
/// <summary>
/// Gets the health status of the component that was checked. The <see cref="Status"/> is based on the pass/fail value of
/// <see cref="HealthCheckResult.Passed"/> and the configured value of <see cref="HealthCheckRegistration.FailureStatus"/>.
/// Gets the health status of the component that was checked.
/// </summary>
public HealthStatus Status { get; }
}

View File

@ -8,10 +8,6 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
/// </summary>
/// <remarks>
/// <para>
/// A health status is derived the pass/fail result of an <see cref="IHealthCheck"/> (<see cref="HealthCheckResult.Result"/>)
/// and the corresponding value of <see cref="HealthCheckRegistration.FailureStatus"/>.
/// </para>
/// <para>
/// A status of <see cref="Unhealthy"/> should be considered the default value for a failing health check. Application
/// developers may configure a health check to report a different status as desired.
/// </para>
@ -23,23 +19,19 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
public enum HealthStatus
{
/// <summary>
/// Indicates that an unexpected exception was thrown when running the health check.
/// Indicates that the health check determined that the component was unhealthy, or an unhandled
/// exception was thrown while executing the health check.
/// </summary>
Failed = 0,
/// <summary>
/// Indicates that the health check determined that the component was unhealthy.
/// </summary>
Unhealthy = 1,
Unhealthy = 0,
/// <summary>
/// Indicates that the health check determined that the component was in a degraded state.
/// </summary>
Degraded = 2,
Degraded = 1,
/// <summary>
/// Indicates that the health check determined that the component was healthy.
/// </summary>
Healthy = 3,
Healthy = 2,
}
}

View File

@ -47,10 +47,10 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
if (await testQuery(_dbContext, cancellationToken))
{
return HealthCheckResult.Passed();
return HealthCheckResult.Healthy();
}
return HealthCheckResult.Failed();
return HealthCheckResult.Unhealthy();
}
}
}

View File

@ -76,7 +76,7 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
var duration = stopwatch.GetElapsedTime();
entry = new HealthReportEntry(
status: result.Result ? HealthStatus.Healthy : registration.FailureStatus,
status: result.Status,
description: result.Description,
duration: duration,
exception: result.Exception,
@ -91,7 +91,7 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
{
var duration = stopwatch.GetElapsedTime();
entry = new HealthReportEntry(
status: HealthStatus.Failed,
status: HealthStatus.Unhealthy,
description: ex.Message,
duration: duration,
exception: ex,
@ -212,10 +212,6 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
case HealthStatus.Unhealthy:
_healthCheckEndUnhealthy(logger, registration.Name, duration.TotalMilliseconds, entry.Status, entry.Description, null);
break;
case HealthStatus.Failed:
_healthCheckEndFailed(logger, registration.Name, duration.TotalMilliseconds, entry.Status, entry.Description, null);
break;
}
}

View File

@ -19,10 +19,6 @@ namespace Microsoft.Extensions.DependencyInjection
/// </summary>
/// <param name="builder">The <see cref="IHealthChecksBuilder"/>.</param>
/// <param name="name">The name of the health check.</param>
/// <param name="failureStatus">
/// The <see cref="HealthStatus"/> that should be reported when the health check reports a failure. If the provided value
/// is <c>null</c>, then <see cref="HealthStatus.Unhealthy"/> will be reported.
/// </param>
/// <param name="tags">A list of tags that can be used to filter health checks.</param>
/// <param name="check">A delegate that provides the health check implementation.</param>
/// <returns>The <see cref="IHealthChecksBuilder"/>.</returns>
@ -30,7 +26,6 @@ namespace Microsoft.Extensions.DependencyInjection
this IHealthChecksBuilder builder,
string name,
Func<HealthCheckResult> check,
HealthStatus? failureStatus = null,
IEnumerable<string> tags = null)
{
if (builder == null)
@ -49,7 +44,7 @@ namespace Microsoft.Extensions.DependencyInjection
}
var instance = new DelegateHealthCheck((ct) => Task.FromResult(check()));
return builder.Add(new HealthCheckRegistration(name, instance, failureStatus, tags));
return builder.Add(new HealthCheckRegistration(name, instance, failureStatus: null, tags));
}
/// <summary>
@ -57,10 +52,6 @@ namespace Microsoft.Extensions.DependencyInjection
/// </summary>
/// <param name="builder">The <see cref="IHealthChecksBuilder"/>.</param>
/// <param name="name">The name of the health check.</param>
/// <param name="failureStatus">
/// The <see cref="HealthStatus"/> that should be reported when the health check reports a failure. If the provided value
/// is <c>null</c>, then <see cref="HealthStatus.Unhealthy"/> will be reported.
/// </param>
/// <param name="tags">A list of tags that can be used to filter health checks.</param>
/// <param name="check">A delegate that provides the health check implementation.</param>
/// <returns>The <see cref="IHealthChecksBuilder"/>.</returns>
@ -68,7 +59,6 @@ namespace Microsoft.Extensions.DependencyInjection
this IHealthChecksBuilder builder,
string name,
Func<CancellationToken, HealthCheckResult> check,
HealthStatus? failureStatus = null,
IEnumerable<string> tags = null)
{
if (builder == null)
@ -87,7 +77,7 @@ namespace Microsoft.Extensions.DependencyInjection
}
var instance = new DelegateHealthCheck((ct) => Task.FromResult(check(ct)));
return builder.Add(new HealthCheckRegistration(name, instance, failureStatus, tags));
return builder.Add(new HealthCheckRegistration(name, instance, failureStatus: null, tags));
}
/// <summary>
@ -95,10 +85,6 @@ namespace Microsoft.Extensions.DependencyInjection
/// </summary>
/// <param name="builder">The <see cref="IHealthChecksBuilder"/>.</param>
/// <param name="name">The name of the health check.</param>
/// <param name="failureStatus">
/// The <see cref="HealthStatus"/> that should be reported when the health check reports a failure. If the provided value
/// is <c>null</c>, then <see cref="HealthStatus.Unhealthy"/> will be reported.
/// </param>
/// <param name="tags">A list of tags that can be used to filter health checks.</param>
/// <param name="check">A delegate that provides the health check implementation.</param>
/// <returns>The <see cref="IHealthChecksBuilder"/>.</returns>
@ -106,7 +92,6 @@ namespace Microsoft.Extensions.DependencyInjection
this IHealthChecksBuilder builder,
string name,
Func<Task<HealthCheckResult>> check,
HealthStatus? failureStatus = null,
IEnumerable<string> tags = null)
{
if (builder == null)
@ -125,7 +110,7 @@ namespace Microsoft.Extensions.DependencyInjection
}
var instance = new DelegateHealthCheck((ct) => check());
return builder.Add(new HealthCheckRegistration(name, instance, failureStatus, tags));
return builder.Add(new HealthCheckRegistration(name, instance, failureStatus: null, tags));
}
/// <summary>
@ -133,10 +118,6 @@ namespace Microsoft.Extensions.DependencyInjection
/// </summary>
/// <param name="builder">The <see cref="IHealthChecksBuilder"/>.</param>
/// <param name="name">The name of the health check.</param>
/// <param name="failureStatus">
/// The <see cref="HealthStatus"/> that should be reported when the health check reports a failure. If the provided value
/// is <c>null</c>, then <see cref="HealthStatus.Unhealthy"/> will be reported.
/// </param>
/// <param name="tags">A list of tags that can be used to filter health checks.</param>
/// <param name="check">A delegate that provides the health check implementation.</param>
/// <returns>The <see cref="IHealthChecksBuilder"/>.</returns>
@ -144,7 +125,6 @@ namespace Microsoft.Extensions.DependencyInjection
this IHealthChecksBuilder builder,
string name,
Func<CancellationToken, Task<HealthCheckResult>> check,
HealthStatus? failureStatus = null,
IEnumerable<string> tags = null)
{
if (builder == null)
@ -163,7 +143,7 @@ namespace Microsoft.Extensions.DependencyInjection
}
var instance = new DelegateHealthCheck((ct) => check(ct));
return builder.Add(new HealthCheckRegistration(name, instance, failureStatus, tags));
return builder.Add(new HealthCheckRegistration(name, instance, failureStatus: null, tags));
}
}
}

View File

@ -110,9 +110,9 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
.ConfigureServices(services =>
{
services.AddHealthChecks()
.AddCheck("Foo", () => HealthCheckResult.Passed("A-ok!"))
.AddCheck("Bar", () => HealthCheckResult.Passed("A-ok!"))
.AddCheck("Baz", () => HealthCheckResult.Passed("A-ok!"));
.AddCheck("Foo", () => HealthCheckResult.Healthy("A-ok!"))
.AddCheck("Bar", () => HealthCheckResult.Healthy("A-ok!"))
.AddCheck("Baz", () => HealthCheckResult.Healthy("A-ok!"));
});
var server = new TestServer(builder);
var client = server.CreateClient();
@ -135,9 +135,9 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
.ConfigureServices(services =>
{
services.AddHealthChecks()
.AddCheck("Foo", () => HealthCheckResult.Passed("A-ok!"))
.AddCheck("Bar", () => HealthCheckResult.Failed("Not so great."), failureStatus: HealthStatus.Degraded)
.AddCheck("Baz", () => HealthCheckResult.Passed("A-ok!"));
.AddCheck("Foo", () => HealthCheckResult.Healthy("A-ok!"))
.AddCheck("Bar", () => HealthCheckResult.Degraded("Not so great."))
.AddCheck("Baz", () => HealthCheckResult.Healthy("A-ok!"));
});
var server = new TestServer(builder);
var client = server.CreateClient();
@ -160,9 +160,9 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
.ConfigureServices(services =>
{
services.AddHealthChecks()
.AddAsyncCheck("Foo", () => Task.FromResult(HealthCheckResult.Passed("A-ok!")))
.AddAsyncCheck("Bar", () => Task.FromResult(HealthCheckResult.Failed("Pretty bad.")))
.AddAsyncCheck("Baz", () => Task.FromResult(HealthCheckResult.Passed("A-ok!")));
.AddAsyncCheck("Foo", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")))
.AddAsyncCheck("Bar", () => Task.FromResult(HealthCheckResult.Unhealthy("Pretty bad.")))
.AddAsyncCheck("Baz", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")));
});
var server = new TestServer(builder);
var client = server.CreateClient();
@ -175,7 +175,7 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
}
[Fact]
public async Task StatusCodeIs500IfCheckIsFailed()
public async Task StatusCodeIs503IfCheckHasUnhandledException()
{
var builder = new WebHostBuilder()
.Configure(app =>
@ -185,18 +185,18 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
.ConfigureServices(services =>
{
services.AddHealthChecks()
.AddAsyncCheck("Foo", () => Task.FromResult(HealthCheckResult.Passed("A-ok!")))
.AddAsyncCheck("Foo", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")))
.AddAsyncCheck("Bar", () => throw null)
.AddAsyncCheck("Baz", () => Task.FromResult(HealthCheckResult.Passed("A-ok!")));
.AddAsyncCheck("Baz", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")));
});
var server = new TestServer(builder);
var client = server.CreateClient();
var response = await client.GetAsync("/health");
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
Assert.Equal("Failed", await response.Content.ReadAsStringAsync());
Assert.Equal("Unhealthy", await response.Content.ReadAsStringAsync());
}
[Fact]
@ -223,9 +223,9 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
.ConfigureServices(services =>
{
services.AddHealthChecks()
.AddAsyncCheck("Foo", () => Task.FromResult(HealthCheckResult.Passed("A-ok!")))
.AddAsyncCheck("Bar", () => Task.FromResult(HealthCheckResult.Failed("Pretty bad.")))
.AddAsyncCheck("Baz", () => Task.FromResult(HealthCheckResult.Passed("A-ok!")));
.AddAsyncCheck("Foo", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")))
.AddAsyncCheck("Bar", () => Task.FromResult(HealthCheckResult.Unhealthy("Pretty bad.")))
.AddAsyncCheck("Baz", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")));
});
var server = new TestServer(builder);
var client = server.CreateClient();
@ -252,9 +252,9 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
.ConfigureServices(services =>
{
services.AddHealthChecks()
.AddAsyncCheck("Foo", () => Task.FromResult(HealthCheckResult.Passed("A-ok!")))
.AddAsyncCheck("Bar", () => Task.FromResult(HealthCheckResult.Failed("Pretty bad.")))
.AddAsyncCheck("Baz", () => Task.FromResult(HealthCheckResult.Passed("A-ok!")));
.AddAsyncCheck("Foo", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")))
.AddAsyncCheck("Bar", () => Task.FromResult(HealthCheckResult.Unhealthy("Pretty bad.")))
.AddAsyncCheck("Baz", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")));
});
var server = new TestServer(builder);
var client = server.CreateClient();
@ -357,10 +357,10 @@ namespace Microsoft.AspNetCore.Diagnostics.HealthChecks
.ConfigureServices(services =>
{
services.AddHealthChecks()
.AddAsyncCheck("Foo", () => Task.FromResult(HealthCheckResult.Passed("A-ok!")))
.AddAsyncCheck("Foo", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")))
// Will get filtered out
.AddAsyncCheck("Bar", () => Task.FromResult(HealthCheckResult.Failed("A-ok!")))
.AddAsyncCheck("Baz", () => Task.FromResult(HealthCheckResult.Passed("A-ok!")));
.AddAsyncCheck("Bar", () => Task.FromResult(HealthCheckResult.Unhealthy("A-ok!")))
.AddAsyncCheck("Baz", () => Task.FromResult(HealthCheckResult.Healthy("A-ok!")));
});
var server = new TestServer(builder);
var client = server.CreateClient();

View File

@ -14,9 +14,9 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
{
public class DbContextHealthCheckTest
{
// Just testing pass here since it would be complicated to simulate a failure. All of that logic lives in EF anyway.
// Just testing healthy here since it would be complicated to simulate a failure. All of that logic lives in EF anyway.
[Fact]
public async Task CheckAsync_DefaultTest_Pass()
public async Task CheckAsync_DefaultTest_Healthy()
{
// Arrange
var services = CreateServices();
@ -29,12 +29,12 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
var result = await check.CheckHealthAsync(new HealthCheckContext() { Registration = registration, });
// Assert
Assert.True(result.Result, "Health check passed");
Assert.Equal(HealthStatus.Healthy, result.Status);
}
}
[Fact]
public async Task CheckAsync_CustomTest_Pass()
public async Task CheckAsync_CustomTest_Healthy()
{
// Arrange
var services = CreateServices(async (c, ct) =>
@ -56,19 +56,18 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
var result = await check.CheckHealthAsync(new HealthCheckContext() { Registration = registration, });
// Assert
Assert.True(result.Result, "Health check passed");
Assert.Equal(HealthStatus.Healthy, result.Status);
}
}
[Fact]
public async Task CheckAsync_CustomTest_Fail()
public async Task CheckAsync_CustomTest_Degraded()
{
// Arrange
var services = CreateServices(async (c, ct) =>
{
return 0 < await c.Blogs.CountAsync();
});
}, failureStatus: HealthStatus.Degraded);
using (var scope = services.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
@ -79,17 +78,41 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
var result = await check.CheckHealthAsync(new HealthCheckContext() { Registration = registration, });
// Assert
Assert.False(result.Result, "Health check failed");
Assert.Equal(HealthStatus.Unhealthy, result.Status);
}
}
private static IServiceProvider CreateServices(Func<TestDbContext, CancellationToken, Task<bool>> testQuery = null)
[Fact]
public async Task CheckAsync_CustomTest_Unhealthy()
{
// Arrange
var services = CreateServices(async (c, ct) =>
{
return 0 < await c.Blogs.CountAsync();
}, failureStatus: HealthStatus.Unhealthy);
using (var scope = services.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var registration = Assert.Single(services.GetRequiredService<IOptions<HealthCheckServiceOptions>>().Value.Registrations);
var check = ActivatorUtilities.CreateInstance<DbContextHealthCheck<TestDbContext>>(scope.ServiceProvider);
// Act
var result = await check.CheckHealthAsync(new HealthCheckContext() { Registration = registration, });
// Assert
Assert.Equal(HealthStatus.Unhealthy, result.Status);
}
}
private static IServiceProvider CreateServices(
Func<TestDbContext, CancellationToken, Task<bool>> testQuery = null,
HealthStatus failureStatus = HealthStatus.Unhealthy)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddDbContext<TestDbContext>(o => o.UseInMemoryDatabase("Test"));
var builder = serviceCollection.AddHealthChecks();
builder.AddDbContextCheck<TestDbContext>("test", HealthStatus.Degraded, new[] { "tag1", "tag2", }, testQuery);
builder.AddDbContextCheck<TestDbContext>("test", failureStatus, new[] { "tag1", "tag2", }, testQuery);
return serviceCollection.BuildServiceProvider();
}
}

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
@ -26,11 +27,11 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
serviceCollection.AddLogging();
serviceCollection.AddOptions();
serviceCollection.AddHealthChecks()
.AddCheck("Foo", new DelegateHealthCheck(_ => Task.FromResult(HealthCheckResult.Passed())))
.AddCheck("Foo", new DelegateHealthCheck(_ => Task.FromResult(HealthCheckResult.Passed())))
.AddCheck("Bar", new DelegateHealthCheck(_ => Task.FromResult(HealthCheckResult.Passed())))
.AddCheck("Baz", new DelegateHealthCheck(_ => Task.FromResult(HealthCheckResult.Passed())))
.AddCheck("Baz", new DelegateHealthCheck(_ => Task.FromResult(HealthCheckResult.Passed())));
.AddCheck("Foo", new DelegateHealthCheck(_ => Task.FromResult(HealthCheckResult.Healthy())))
.AddCheck("Foo", new DelegateHealthCheck(_ => Task.FromResult(HealthCheckResult.Healthy())))
.AddCheck("Bar", new DelegateHealthCheck(_ => Task.FromResult(HealthCheckResult.Healthy())))
.AddCheck("Baz", new DelegateHealthCheck(_ => Task.FromResult(HealthCheckResult.Healthy())))
.AddCheck("Baz", new DelegateHealthCheck(_ => Task.FromResult(HealthCheckResult.Healthy())));
var services = serviceCollection.BuildServiceProvider();
@ -63,16 +64,25 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
var service = CreateHealthChecksService(b =>
{
b.AddAsyncCheck("HealthyCheck", _ => Task.FromResult(HealthCheckResult.Passed(HealthyMessage, data)));
b.AddAsyncCheck("DegradedCheck", _ => Task.FromResult(HealthCheckResult.Failed(DegradedMessage)), failureStatus: HealthStatus.Degraded);
b.AddAsyncCheck("UnhealthyCheck", _ => Task.FromResult(HealthCheckResult.Failed(UnhealthyMessage, exception)));
b.AddAsyncCheck("HealthyCheck", _ => Task.FromResult(HealthCheckResult.Healthy(HealthyMessage, data)));
b.AddAsyncCheck("DegradedCheck", _ => Task.FromResult(HealthCheckResult.Degraded(DegradedMessage)));
b.AddAsyncCheck("UnhealthyCheck", _ => Task.FromResult(HealthCheckResult.Unhealthy(UnhealthyMessage, exception)));
});
// Act
var results = await service.CheckHealthAsync();
// Assert
Assert.Collection(results.Entries,
Assert.Collection(
results.Entries.OrderBy(kvp => kvp.Key),
actual =>
{
Assert.Equal("DegradedCheck", actual.Key);
Assert.Equal(DegradedMessage, actual.Value.Description);
Assert.Equal(HealthStatus.Degraded, actual.Value.Status);
Assert.Null(actual.Value.Exception);
Assert.Empty(actual.Value.Data);
},
actual =>
{
Assert.Equal("HealthyCheck", actual.Key);
@ -86,14 +96,6 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
});
},
actual =>
{
Assert.Equal("DegradedCheck", actual.Key);
Assert.Equal(DegradedMessage, actual.Value.Description);
Assert.Equal(HealthStatus.Degraded, actual.Value.Status);
Assert.Null(actual.Value.Exception);
Assert.Empty(actual.Value.Data);
},
actual =>
{
Assert.Equal("UnhealthyCheck", actual.Key);
Assert.Equal(UnhealthyMessage, actual.Value.Description);
@ -121,9 +123,9 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
var service = CreateHealthChecksService(b =>
{
b.AddAsyncCheck("HealthyCheck", _ => Task.FromResult(HealthCheckResult.Passed(HealthyMessage, data)));
b.AddAsyncCheck("DegradedCheck", _ => Task.FromResult(HealthCheckResult.Failed(DegradedMessage)), failureStatus: HealthStatus.Degraded);
b.AddAsyncCheck("UnhealthyCheck", _ => Task.FromResult(HealthCheckResult.Failed(UnhealthyMessage, exception)));
b.AddAsyncCheck("HealthyCheck", _ => Task.FromResult(HealthCheckResult.Healthy(HealthyMessage, data)));
b.AddAsyncCheck("DegradedCheck", _ => Task.FromResult(HealthCheckResult.Degraded(DegradedMessage)));
b.AddAsyncCheck("UnhealthyCheck", _ => Task.FromResult(HealthCheckResult.Unhealthy(UnhealthyMessage, exception)));
});
// Act
@ -201,7 +203,7 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
insideCheck.SetResult(null);
await Task.Delay(10000, ct);
return HealthCheckResult.Failed();
return HealthCheckResult.Unhealthy();
});
});
@ -218,7 +220,7 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
}
[Fact]
public async Task CheckHealthAsync_ConvertsExceptionInHealthCheckToFailedResultAsync()
public async Task CheckHealthAsync_ConvertsExceptionInHealthCheckToUnhealthyResultAsync()
{
// Arrange
var thrownException = new InvalidOperationException("Whoops!");
@ -228,7 +230,7 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
{
b.AddAsyncCheck("Throws", ct => throw thrownException);
b.AddAsyncCheck("Faults", ct => Task.FromException<HealthCheckResult>(faultedException));
b.AddAsyncCheck("Succeeds", ct => Task.FromResult(HealthCheckResult.Passed()));
b.AddAsyncCheck("Succeeds", ct => Task.FromResult(HealthCheckResult.Healthy()));
});
// Act
@ -241,14 +243,14 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
{
Assert.Equal("Throws", actual.Key);
Assert.Equal(thrownException.Message, actual.Value.Description);
Assert.Equal(HealthStatus.Failed, actual.Value.Status);
Assert.Equal(HealthStatus.Unhealthy, actual.Value.Status);
Assert.Same(thrownException, actual.Value.Exception);
},
actual =>
{
Assert.Equal("Faults", actual.Key);
Assert.Equal(faultedException.Message, actual.Value.Description);
Assert.Equal(HealthStatus.Failed, actual.Value.Status);
Assert.Equal(HealthStatus.Unhealthy, actual.Value.Status);
Assert.Same(faultedException, actual.Value.Exception);
},
actual =>
@ -278,7 +280,7 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
Assert.Equal("TestScope", item.Value);
});
});
return Task.FromResult(HealthCheckResult.Passed());
return Task.FromResult(HealthCheckResult.Healthy());
});
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
@ -398,7 +400,7 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
return Task.FromResult(HealthCheckResult.Passed());
return Task.FromResult(HealthCheckResult.Healthy());
}
}
@ -410,7 +412,7 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
{
{ "name", context.Registration.Name },
};
return Task.FromResult(HealthCheckResult.Passed(data: data));
return Task.FromResult(HealthCheckResult.Healthy(data: data));
}
}
}

View File

@ -20,7 +20,7 @@ namespace Microsoft.Extensions.DependencyInjection
// Arrange
var instance = new DelegateHealthCheck((_) =>
{
return Task.FromResult(HealthCheckResult.Passed());
return Task.FromResult(HealthCheckResult.Healthy());
});
var services = CreateServices();
@ -112,9 +112,9 @@ namespace Microsoft.Extensions.DependencyInjection
{
// Arrange
var services = CreateServices();
services.AddHealthChecks().AddCheck("test", failureStatus: HealthStatus.Degraded, tags: new[] { "tag", }, check: () =>
services.AddHealthChecks().AddCheck("test", tags: new[] { "tag", }, check: () =>
{
return HealthCheckResult.Passed();
return HealthCheckResult.Healthy();
});
var serviceProvider = services.BuildServiceProvider();
@ -125,7 +125,7 @@ namespace Microsoft.Extensions.DependencyInjection
// Assert
var registration = Assert.Single(options.Registrations);
Assert.Equal("test", registration.Name);
Assert.Equal(HealthStatus.Degraded, registration.FailureStatus);
Assert.Equal(HealthStatus.Unhealthy, registration.FailureStatus);
Assert.Equal<string>(new[] { "tag", }, registration.Tags);
Assert.IsType<DelegateHealthCheck>(registration.Factory(serviceProvider));
}
@ -137,8 +137,8 @@ namespace Microsoft.Extensions.DependencyInjection
var services = CreateServices();
services.AddHealthChecks().AddCheck("test", (_) =>
{
return HealthCheckResult.Passed();
}, failureStatus: HealthStatus.Degraded, tags: new[] { "tag", });
return HealthCheckResult.Degraded();
}, tags: new[] { "tag", });
var serviceProvider = services.BuildServiceProvider();
@ -148,7 +148,7 @@ namespace Microsoft.Extensions.DependencyInjection
// Assert
var registration = Assert.Single(options.Registrations);
Assert.Equal("test", registration.Name);
Assert.Equal(HealthStatus.Degraded, registration.FailureStatus);
Assert.Equal(HealthStatus.Unhealthy, registration.FailureStatus);
Assert.Equal<string>(new[] { "tag", }, registration.Tags);
Assert.IsType<DelegateHealthCheck>(registration.Factory(serviceProvider));
}
@ -160,8 +160,8 @@ namespace Microsoft.Extensions.DependencyInjection
var services = CreateServices();
services.AddHealthChecks().AddAsyncCheck("test", () =>
{
return Task.FromResult(HealthCheckResult.Passed());
}, failureStatus: HealthStatus.Degraded, tags: new[] { "tag", });
return Task.FromResult(HealthCheckResult.Healthy());
}, tags: new[] { "tag", });
var serviceProvider = services.BuildServiceProvider();
@ -171,7 +171,7 @@ namespace Microsoft.Extensions.DependencyInjection
// Assert
var registration = Assert.Single(options.Registrations);
Assert.Equal("test", registration.Name);
Assert.Equal(HealthStatus.Degraded, registration.FailureStatus);
Assert.Equal(HealthStatus.Unhealthy, registration.FailureStatus);
Assert.Equal<string>(new[] { "tag", }, registration.Tags);
Assert.IsType<DelegateHealthCheck>(registration.Factory(serviceProvider));
}
@ -183,8 +183,8 @@ namespace Microsoft.Extensions.DependencyInjection
var services = CreateServices();
services.AddHealthChecks().AddAsyncCheck("test", (_) =>
{
return Task.FromResult(HealthCheckResult.Passed());
}, failureStatus: HealthStatus.Degraded, tags: new[] { "tag", });
return Task.FromResult(HealthCheckResult.Unhealthy());
}, tags: new[] { "tag", });
var serviceProvider = services.BuildServiceProvider();
@ -194,7 +194,7 @@ namespace Microsoft.Extensions.DependencyInjection
// Assert
var registration = Assert.Single(options.Registrations);
Assert.Equal("test", registration.Name);
Assert.Equal(HealthStatus.Degraded, registration.FailureStatus);
Assert.Equal(HealthStatus.Unhealthy, registration.FailureStatus);
Assert.Equal<string>(new[] { "tag", }, registration.Tags);
Assert.IsType<DelegateHealthCheck>(registration.Factory(serviceProvider));
}
@ -205,10 +205,10 @@ namespace Microsoft.Extensions.DependencyInjection
var services = new ServiceCollection();
services
.AddHealthChecks()
.AddAsyncCheck("Foo", () => Task.FromResult(HealthCheckResult.Passed()));
.AddAsyncCheck("Foo", () => Task.FromResult(HealthCheckResult.Healthy()));
services
.AddHealthChecks()
.AddAsyncCheck("Bar", () => Task.FromResult(HealthCheckResult.Passed()));
.AddAsyncCheck("Bar", () => Task.FromResult(HealthCheckResult.Healthy()));
// Act
var options = services.BuildServiceProvider().GetRequiredService<IOptions<HealthCheckServiceOptions>>();

View File

@ -448,8 +448,8 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
serviceCollection.AddOptions();
serviceCollection.AddLogging();
serviceCollection.AddHealthChecks()
.AddCheck("one", () => { return HealthCheckResult.Passed(); })
.AddCheck("two", () => { return HealthCheckResult.Passed(); });
.AddCheck("one", () => { return HealthCheckResult.Healthy(); })
.AddCheck("two", () => { return HealthCheckResult.Healthy(); });
// Choosing big values for tests to make sure that we're not dependent on the defaults.
// All of the tests that rely on the timer will set their own values for speed.

View File

@ -13,7 +13,6 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks
[InlineData(HealthStatus.Healthy)]
[InlineData(HealthStatus.Degraded)]
[InlineData(HealthStatus.Unhealthy)]
[InlineData(HealthStatus.Failed)]
public void Status_MatchesWorstStatusInResults(HealthStatus status)
{
var result = new HealthReport(new Dictionary<string, HealthReportEntry>()