Skip to content

Commit

Permalink
Expose AddTcpEndpointProbe (#4892)
Browse files Browse the repository at this point in the history
* Expose AddTcpEndpointProbe
  • Loading branch information
joegoldman2 authored Jan 20, 2024
1 parent 855b57b commit 62c78ee
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 144 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public static IServiceCollection AddKubernetesProbes(this IServiceCollection ser
var wrapperOptions = new KubernetesProbesOptions();

return services
.AddTcpEndpointHealthCheck(ProbeTags.Liveness, options =>
.AddTcpEndpointProbe(ProbeTags.Liveness, options =>
{
wrapperOptions.LivenessProbe = options;
configure(wrapperOptions);
Expand All @@ -64,7 +64,7 @@ public static IServiceCollection AddKubernetesProbes(this IServiceCollection ser
options.FilterChecks = (check) => check.Tags.Contains(ProbeTags.Liveness) && originalPredicate(check);
}
})
.AddTcpEndpointHealthCheck(ProbeTags.Startup, options =>
.AddTcpEndpointProbe(ProbeTags.Startup, options =>
{
wrapperOptions.StartupProbe = options;
configure(wrapperOptions);
Expand All @@ -78,7 +78,7 @@ public static IServiceCollection AddKubernetesProbes(this IServiceCollection ser
options.FilterChecks = (check) => check.Tags.Contains(ProbeTags.Startup) && originalPredicate(check);
}
})
.AddTcpEndpointHealthCheck(ProbeTags.Readiness, (options) =>
.AddTcpEndpointProbe(ProbeTags.Readiness, (options) =>
{
wrapperOptions.ReadinessProbe = options;
configure(wrapperOptions);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Microsoft.Extensions.Diagnostics.Probes;
/// <summary>
/// Options for Kubernetes probes.
/// </summary>
public partial class KubernetesProbesOptions
public class KubernetesProbesOptions
{
private const int DefaultLivenessProbePort = 2305;
private const int DefaultStartupProbePort = 2306;
Expand All @@ -18,7 +18,7 @@ public partial class KubernetesProbesOptions
/// <remarks>
/// Default port is 2305.
/// </remarks>
public EndpointOptions LivenessProbe { get; set; } = new EndpointOptions
public TcpEndpointProbesOptions LivenessProbe { get; set; } = new TcpEndpointProbesOptions
{
TcpPort = DefaultLivenessProbePort,
};
Expand All @@ -29,7 +29,7 @@ public partial class KubernetesProbesOptions
/// <remarks>
/// Default port is 2306.
/// </remarks>
public EndpointOptions StartupProbe { get; set; } = new EndpointOptions
public TcpEndpointProbesOptions StartupProbe { get; set; } = new TcpEndpointProbesOptions
{
TcpPort = DefaultStartupProbePort,
};
Expand All @@ -40,7 +40,7 @@ public partial class KubernetesProbesOptions
/// <remarks>
/// Default port is 2307.
/// </remarks>
public EndpointOptions ReadinessProbe { get; set; } = new EndpointOptions
public TcpEndpointProbesOptions ReadinessProbe { get; set; } = new TcpEndpointProbesOptions
{
TcpPort = DefaultReadinessProbePort,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,29 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Diagnostics.Probes;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.Shared.Diagnostics;

namespace Microsoft.Extensions.Diagnostics.Probes;
namespace Microsoft.Extensions.DependencyInjection;

/// <summary>
/// Extension methods for <see cref="TcpEndpointHealthCheckService" /> for <see cref="IServiceCollection" />.
/// Extension methods for setting up TCP-based health check probes.
/// </summary>
internal static class TcpEndpointHealthCheckExtensions
public static class TcpEndpointProbesExtensions
{
/// <summary>
/// Registers health status reporting using a TCP port
/// if service is considered as healthy <see cref="IHealthCheck"/>.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection" /> to add the services to.</param>
/// <returns>The value of <paramref name="services"/>.</returns>
internal static IServiceCollection AddTcpEndpointHealthCheck(this IServiceCollection services)
public static IServiceCollection AddTcpEndpointProbe(this IServiceCollection services)
{
_ = Throw.IfNull(services);

return services.AddTcpEndpointHealthCheck(Microsoft.Extensions.Options.Options.DefaultName);
return services.AddTcpEndpointProbe(Microsoft.Extensions.Options.Options.DefaultName);
}

/// <summary>
Expand All @@ -36,19 +37,19 @@ internal static IServiceCollection AddTcpEndpointHealthCheck(this IServiceCollec
/// <param name="services">The <see cref="IServiceCollection" /> to add the services to.</param>
/// <param name="name">Name used to retrieve the options.</param>
/// <returns>The value of <paramref name="services"/>.</returns>
internal static IServiceCollection AddTcpEndpointHealthCheck(this IServiceCollection services, string name)
public static IServiceCollection AddTcpEndpointProbe(this IServiceCollection services, string name)
{
_ = Throw.IfNull(services);

_ = services.AddHealthChecks();

_ = services
.AddOptionsWithValidateOnStart<KubernetesProbesOptions.EndpointOptions, EndpointOptionsValidator>(name);
.AddOptionsWithValidateOnStart<TcpEndpointProbesOptions, TcpEndpointProbesOptionsValidator>(name);

_ = services.AddSingleton<IHostedService>(provider =>
{
var options = provider.GetRequiredService<IOptionsMonitor<KubernetesProbesOptions.EndpointOptions>>().Get(name);
return ActivatorUtilities.CreateInstance<TcpEndpointHealthCheckService>(provider, options);
var options = provider.GetRequiredService<IOptionsMonitor<TcpEndpointProbesOptions>>().Get(name);
return ActivatorUtilities.CreateInstance<TcpEndpointProbesService>(provider, options);
});

return services;
Expand All @@ -59,18 +60,18 @@ internal static IServiceCollection AddTcpEndpointHealthCheck(this IServiceCollec
/// if service is considered as healthy <see cref="IHealthCheck"/>.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection" /> to add the services to.</param>
/// <param name="configure">Configuration for <see cref="KubernetesProbesOptions.EndpointOptions"/>.</param>
/// <param name="configure">Configuration for <see cref="TcpEndpointProbesOptions"/>.</param>
/// <returns>The value of <paramref name="services"/>.</returns>
internal static IServiceCollection AddTcpEndpointHealthCheck(
public static IServiceCollection AddTcpEndpointProbe(
this IServiceCollection services,
Action<KubernetesProbesOptions.EndpointOptions> configure)
Action<TcpEndpointProbesOptions> configure)
{
_ = Throw.IfNull(services);
_ = Throw.IfNull(configure);

_ = services.Configure(configure);

return services.AddTcpEndpointHealthCheck();
return services.AddTcpEndpointProbe();
}

/// <summary>
Expand All @@ -79,38 +80,38 @@ internal static IServiceCollection AddTcpEndpointHealthCheck(
/// </summary>
/// <param name="services">The <see cref="IServiceCollection" /> to add the services to.</param>
/// <param name="name">Name for the options.</param>
/// <param name="configure">Configuration for <see cref="KubernetesProbesOptions.EndpointOptions"/>.</param>
/// <param name="configure">Configuration for <see cref="TcpEndpointProbesOptions"/>.</param>
/// <returns>The value of <paramref name="services"/>.</returns>
internal static IServiceCollection AddTcpEndpointHealthCheck(
public static IServiceCollection AddTcpEndpointProbe(
this IServiceCollection services,
string name,
Action<KubernetesProbesOptions.EndpointOptions> configure)
Action<TcpEndpointProbesOptions> configure)
{
_ = Throw.IfNull(services);
_ = Throw.IfNull(configure);

_ = services.Configure(name, configure);

return services.AddTcpEndpointHealthCheck(name);
return services.AddTcpEndpointProbe(name);
}

/// <summary>
/// Registers health status reporting using a TCP port
/// if service is considered as healthy <see cref="IHealthCheck"/>.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection" /> to add the services to.</param>
/// <param name="configurationSection">Configuration for <see cref="KubernetesProbesOptions.EndpointOptions"/>.</param>
/// <param name="configurationSection">Configuration for <see cref="TcpEndpointProbesOptions"/>.</param>
/// <returns>The value of <paramref name="services"/>.</returns>
internal static IServiceCollection AddTcpEndpointHealthCheck(
public static IServiceCollection AddTcpEndpointProbe(
this IServiceCollection services,
IConfigurationSection configurationSection)
{
_ = Throw.IfNull(services);
_ = Throw.IfNull(configurationSection);

_ = services.Configure<KubernetesProbesOptions.EndpointOptions>(configurationSection);
_ = services.Configure<TcpEndpointProbesOptions>(configurationSection);

return services.AddTcpEndpointHealthCheck();
return services.AddTcpEndpointProbe();
}

/// <summary>
Expand All @@ -119,18 +120,18 @@ internal static IServiceCollection AddTcpEndpointHealthCheck(
/// </summary>
/// <param name="services">The <see cref="IServiceCollection" /> to add the services to.</param>
/// <param name="name">Name for the options.</param>
/// <param name="configurationSection">Configuration for <see cref="KubernetesProbesOptions.EndpointOptions"/>.</param>
/// <param name="configurationSection">Configuration for <see cref="TcpEndpointProbesOptions"/>.</param>
/// <returns>The value of <paramref name="services"/>.</returns>
internal static IServiceCollection AddTcpEndpointHealthCheck(
public static IServiceCollection AddTcpEndpointProbe(
this IServiceCollection services,
string name,
IConfigurationSection configurationSection)
{
_ = Throw.IfNull(services);
_ = Throw.IfNull(configurationSection);

_ = services.Configure<KubernetesProbesOptions.EndpointOptions>(name, configurationSection);
_ = services.Configure<TcpEndpointProbesOptions>(name, configurationSection);

return services.AddTcpEndpointHealthCheck(name);
return services.AddTcpEndpointProbe(name);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Shared.Data.Validation;

namespace Microsoft.Extensions.Diagnostics.Probes;

/// <summary>
/// Options to control TCP-based health check probes.
/// </summary>
[SuppressMessage("Major Code Smell", "S109:Magic numbers should not be used", Justification = "In place numbers make the ranges cleaner")]
public class TcpEndpointProbesOptions
{
private const int DefaultMaxPendingConnections = 10;
private const int DefaultTcpPort = 2305;

/// <summary>
/// Gets or sets the TCP port that gets opened if the service is healthy and closed otherwise.
/// </summary>
/// <value>
/// The default value is 2305.
/// </value>
[Range(1, 65535)]
public int TcpPort { get; set; } = DefaultTcpPort;

/// <summary>
/// Gets or sets the maximum length of the pending connections queue.
/// </summary>
/// <value>
/// The default value is 10.
/// </value>
[Range(1, 10000)]
public int MaxPendingConnections { get; set; } = DefaultMaxPendingConnections;

/// <summary>
/// Gets or sets the interval at which the health of the application is assessed.
/// </summary>
/// <value>
/// The default value is 30 seconds.
/// </value>
[TimeSpan("00:00:05", "00:05:00")]
public TimeSpan HealthAssessmentPeriod { get; set; } = TimeSpan.FromSeconds(30);

/// <summary>
/// Gets or sets a predicate that is used to include health checks based on user-defined criteria.
/// </summary>
/// <value>
/// The default value is <see langword="null" />, which has the effect of enabling all health checks.
/// </value>
public Func<HealthCheckRegistration, bool>? FilterChecks { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
namespace Microsoft.Extensions.Diagnostics.Probes;

[OptionsValidator]
internal sealed partial class EndpointOptionsValidator : IValidateOptions<KubernetesProbesOptions.EndpointOptions>
internal sealed partial class TcpEndpointProbesOptionsValidator : IValidateOptions<TcpEndpointProbesOptions>
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,18 @@ namespace Microsoft.Extensions.Diagnostics.Probes;
/// <summary>
/// Opens a TCP port if the service is healthy and closes it otherwise.
/// </summary>
internal sealed class TcpEndpointHealthCheckService : BackgroundService
internal sealed class TcpEndpointProbesService : BackgroundService
{
internal TimeProvider TimeProvider { get; set; } = TimeProvider.System;

private readonly ILogger<TcpEndpointHealthCheckService> _logger;
private readonly ILogger<TcpEndpointProbesService> _logger;
private readonly HealthCheckService _healthCheckService;
private readonly KubernetesProbesOptions.EndpointOptions _options;
#pragma warning disable CA2213 // 'TcpEndpointHealthCheckService' contains field '_listener' that is of IDisposable type 'TcpListener'
private readonly TcpEndpointProbesOptions _options;
#pragma warning disable CA2213 // 'TcpEndpointProbesService' contains field '_listener' that is of IDisposable type 'TcpListener'
private readonly TcpListener _listener;
#pragma warning restore CA2213

public TcpEndpointHealthCheckService(ILogger<TcpEndpointHealthCheckService> logger, HealthCheckService healthCheckService, KubernetesProbesOptions.EndpointOptions options)
public TcpEndpointProbesService(ILogger<TcpEndpointProbesService> logger, HealthCheckService healthCheckService, TcpEndpointProbesOptions options)
{
_logger = logger;
_healthCheckService = healthCheckService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ public void AddKubernetesProbes_RegistersAllProbes()
services.AddKubernetesProbes().AddHealthChecks();
});

var hostedServices = host.Services.GetServices<IHostedService>().Where(service => service.GetType().Name == "TcpEndpointHealthCheckService");
var configurations = host.Services.GetServices<IOptionsMonitor<KubernetesProbesOptions.EndpointOptions>>();
var hostedServices = host.Services.GetServices<IHostedService>().Where(service => service.GetType().Name == "TcpEndpointProbesService");
var configurations = host.Services.GetServices<IOptionsMonitor<TcpEndpointProbesOptions>>();

Assert.Equal(3, hostedServices.Count());
Assert.Single(configurations);
Expand Down Expand Up @@ -74,8 +74,8 @@ public void AddKubernetesProbes_WithConfigureAction_RegistersAllProbes()
}).AddHealthChecks();
});

var hostedServices = host.Services.GetServices<IHostedService>().Where(service => service.GetType().Name == "TcpEndpointHealthCheckService");
var configurations = host.Services.GetServices<IOptionsMonitor<KubernetesProbesOptions.EndpointOptions>>();
var hostedServices = host.Services.GetServices<IHostedService>().Where(service => service.GetType().Name == "TcpEndpointProbesService");
var configurations = host.Services.GetServices<IOptionsMonitor<TcpEndpointProbesOptions>>();

Assert.Equal(3, hostedServices.Count());
Assert.Single(configurations);
Expand All @@ -102,8 +102,8 @@ public void AddKubernetesProbes_WithConfigurationSection_RegistersAllProbes()
services.AddKubernetesProbes(configuration.GetSection("KubernetesProbes")).AddHealthChecks();
});

var hostedServices = host.Services.GetServices<IHostedService>().Where(service => service.GetType().Name == "TcpEndpointHealthCheckService");
var configurations = host.Services.GetServices<IOptionsMonitor<KubernetesProbesOptions.EndpointOptions>>();
var hostedServices = host.Services.GetServices<IHostedService>().Where(service => service.GetType().Name == "TcpEndpointProbesService");
var configurations = host.Services.GetServices<IOptionsMonitor<TcpEndpointProbesOptions>>();

Assert.Equal(3, hostedServices.Count());
Assert.Single(configurations);
Expand Down
Loading

0 comments on commit 62c78ee

Please sign in to comment.