Skip to content

Commit

Permalink
Registration methods for EventStore TCP+gRPC passing in the ServicePr…
Browse files Browse the repository at this point in the history
…ovider (#1538)
  • Loading branch information
NielsPilgaard authored Nov 11, 2022
1 parent 3b3f24f commit 734688e
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 2 deletions.
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.ShouldBe("eventstore");
check.ShouldBeOfType<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 @@ -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) { }
}
}

0 comments on commit 734688e

Please sign in to comment.