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

Registration methods for EventStore TCP+gRPC passing in the ServiceProvider #1538

Merged
merged 11 commits into from
Nov 11, 2022
Merged
Show file tree
Hide file tree
Changes from 9 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 @@ -39,4 +39,34 @@ public static IHealthChecksBuilder AddEventStore(
tags,
timeout));
}

/// <summary>
/// Add a health check for EventStore services.
/// </summary>
/// <param name="builder">The <see cref="IHealthChecksBuilder"/>.</param>
/// <param name="connectionStringFactory">A function returning the EventStore connection string to be used.</param>
/// <param name="name">The health check name. Optional. If <c>null</c> the type name 'eventstore' will be used for the name.</param>
/// <param name="failureStatus">
/// The <see cref="HealthStatus"/> that should be reported when the health check fails. Optional. If <c>null</c> then
/// the default status of <see cref="HealthStatus.Unhealthy"/> will be reported.
/// </param>
/// <param name="tags">A list of tags that can be used to filter sets of health checks. Optional.</param>
/// <param name="timeout">An optional <see cref="TimeSpan"/> representing the timeout of the check.</param>
/// <returns>The specified <paramref name="builder"/>.</returns>
public static IHealthChecksBuilder AddEventStore(
this IHealthChecksBuilder builder,
Func<IServiceProvider, string> connectionStringFactory,
string? name = default,
HealthStatus? failureStatus = default,
IEnumerable<string>? tags = default,
TimeSpan? timeout = default)
{
builder.Services.AddSingleton(sp => new EventStoreHealthCheck(connectionStringFactory(sp)));
return builder.Add(new HealthCheckRegistration(
name ?? NAME,
sp => sp.GetRequiredService<EventStoreHealthCheck>(),
failureStatus,
tags,
timeout));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,38 @@ public static IHealthChecksBuilder AddEventStore(
tags,
timeout));
}

/// <summary>
/// Add a health check for EventStore services.
/// </summary>
/// <param name="builder">The <see cref="IHealthChecksBuilder"/>.</param>
/// <param name="eventStoreConnectionFactory">A function returning the EventStore connection string to be used.</param>
/// <param name="login">The EventStore user login. Optional. If <c>null</c> the healthcheck will be processed without authentication.</param>
/// <param name="password">The EventStore user password. Optional. If <c>null</c> the healthcheck will be processed without authentication.</param>
/// <param name="name">The health check name. Optional. If <c>null</c> the type name 'eventstore' will be used for the name.</param>
/// <param name="failureStatus">
/// The <see cref="HealthStatus"/> that should be reported when the health check fails. Optional. If <c>null</c> then
/// the default status of <see cref="HealthStatus.Unhealthy"/> will be reported.
/// </param>
/// <param name="tags">A list of tags that can be used to filter sets of health checks. Optional.</param>
/// <param name="timeout">An optional <see cref="TimeSpan"/> representing the timeout of the check.</param>
/// <returns>The specified <paramref name="builder"/>.</returns>
public static IHealthChecksBuilder AddEventStore(
this IHealthChecksBuilder builder,
Func<IServiceProvider, string> eventStoreConnectionFactory,
string? login = default,
string? password = default,
string? name = default,
HealthStatus? failureStatus = default,
IEnumerable<string>? tags = default,
TimeSpan? timeout = default)
{
return builder.Add(new HealthCheckRegistration(
name ?? NAME,
sp => new EventStoreHealthCheck(eventStoreConnectionFactory(sp), login, password),
failureStatus,
tags,
timeout));
}
}
}
2 changes: 1 addition & 1 deletion src/HealthChecks.EventStore/EventStoreHealthCheck.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context
connectionSettings,
CONNECTION_NAME))
{
var tcs = new TaskCompletionSource<HealthCheckResult>();
var tcs = new TaskCompletionSource<HealthCheckResult>(TaskCreationOptions.RunContinuationsAsynchronously);

//connected
connection.Connected += (s, e) => tcs.TrySetResult(HealthCheckResult.Healthy());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,23 @@ public void add_health_check_when_properly_configured()
check.GetType().Should().Be(typeof(EventStoreHealthCheck));
}

[Fact]
public void add_health_check_when_properly_configured_using_service_provider_overload()
{
var services = new ServiceCollection();
services.AddHealthChecks()
.AddEventStore(sp => "connection-string");

using var serviceProvider = services.BuildServiceProvider();
var options = serviceProvider.GetRequiredService<IOptions<HealthCheckServiceOptions>>();

var registration = options.Value.Registrations.First();
var check = registration.Factory(serviceProvider);

registration.Name.Should().Be("eventstore");
check.GetType().Should().Be(typeof(EventStoreHealthCheck));
}

[Fact]
public void add_named_health_check_when_properly_configured()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,9 @@ public async Task be_unhealthy_if_eventstore_is_not_available()
var webHostBuilder = new WebHostBuilder()
.ConfigureServices(services =>
{
// Existing hostname, incorrect port. If the hostname cannot be reached, CreateRequest will hang.
services.AddHealthChecks()
.AddEventStore("tcp://nonexistingdomain:1113", tags: new string[] { "eventstore" });
.AddEventStore("ConnectTo=tcp://localhost:1114; UseSslConnection=false; HeartBeatTimeout=500", tags: new string[] { "eventstore" });
})
.Configure(app =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace Microsoft.Extensions.DependencyInjection
{
public static class EventStoreHealthCheckBuilderExtensions
{
public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddEventStore(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, System.Func<System.IServiceProvider, string> eventStoreConnectionFactory, string? login = null, string? password = null, string? name = null, Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus? failureStatus = default, System.Collections.Generic.IEnumerable<string>? tags = null, System.TimeSpan? timeout = default) { }
public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddEventStore(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, string eventStoreConnection, string? login = null, string? password = null, string? name = null, Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus? failureStatus = default, System.Collections.Generic.IEnumerable<string>? tags = null, System.TimeSpan? timeout = default) { }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,23 @@ public void add_health_check_when_properly_configured()
check.GetType().Should().Be(typeof(EventStoreHealthCheck));
}

[Fact]
public void add_health_check_when_properly_configured_using_service_provider_overload()
{
var services = new ServiceCollection();
services.AddHealthChecks()
.AddEventStore(sp => "esdb://localhost:2113?tls=false");

using var serviceProvider = services.BuildServiceProvider();
var options = serviceProvider.GetRequiredService<IOptions<HealthCheckServiceOptions>>();

var registration = options.Value.Registrations.First();
var check = registration.Factory(serviceProvider);

registration.Name.Should().Be("eventstore");
sungam3r marked this conversation as resolved.
Show resolved Hide resolved
check.ShouldBeOfType<ApplicationStatusHealthCheck>();
sungam3r marked this conversation as resolved.
Show resolved Hide resolved
}

[Fact]
public void add_named_health_check_when_properly_configured()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace Microsoft.Extensions.DependencyInjection
{
public static class EventStoreHealthCheckBuilderExtensions
{
public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddEventStore(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, System.Func<System.IServiceProvider, string> connectionStringFactory, string? name = null, Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus? failureStatus = default, System.Collections.Generic.IEnumerable<string>? tags = null, System.TimeSpan? timeout = default) { }
public static Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder AddEventStore(this Microsoft.Extensions.DependencyInjection.IHealthChecksBuilder builder, string connectionString, string? name = null, Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus? failureStatus = default, System.Collections.Generic.IEnumerable<string>? tags = null, System.TimeSpan? timeout = default) { }
}
}