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

Added MySQL HealthChecks Query and Callback support. #1835

Merged
merged 15 commits into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
@@ -1,5 +1,6 @@
using HealthChecks.MySql;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using MySqlConnector;

namespace Microsoft.Extensions.DependencyInjection;

Expand All @@ -9,13 +10,16 @@ namespace Microsoft.Extensions.DependencyInjection;
public static class MySqlHealthCheckBuilderExtensions
{
private const string NAME = "mysql";
internal const string HEALTH_QUERY = "SELECT 1;";

/// <summary>
/// Add a health check for MySql databases.
/// Add a health check for MySQL/MariaDB Server databases.
sungam3r marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
/// <param name="builder">The <see cref="IHealthChecksBuilder"/>.</param>
/// <param name="connectionString">The MySql connection string to be used.</param>
/// <param name="name">The health check name. Optional. If <c>null</c> the type name 'mysql' will be used for the name.</param>
/// <param name="connectionString">The Sql Server connection string to be used.</param>
turric4n marked this conversation as resolved.
Show resolved Hide resolved
/// <param name="healthQuery">The query to be executed.</param>
/// <param name="configure">An optional action to allow additional SQL Server specific configuration.</param>
/// <param name="name">The health check name. Optional. If <c>null</c> the type name 'sqlserver' 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.
Expand All @@ -26,14 +30,86 @@ public static class MySqlHealthCheckBuilderExtensions
public static IHealthChecksBuilder AddMySql(
this IHealthChecksBuilder builder,
string connectionString,
string healthQuery = HEALTH_QUERY,
Action<MySqlConnection>? configure = null,
string? name = default,
HealthStatus? failureStatus = default,
IEnumerable<string>? tags = default,
TimeSpan? timeout = default)
{
return builder.AddMySql(_ => connectionString, healthQuery, configure, name, failureStatus, tags, timeout);
}

/// <summary>
/// Add a health check for MySQL/MariaDB Server databases.
/// </summary>
/// <param name="builder">The <see cref="IHealthChecksBuilder"/>.</param>
/// <param name="connectionStringFactory">A factory to build the SQL Server connection string to use.</param>
/// <param name="healthQuery">The query to be executed.</param>
/// <param name="configure">An optional action to allow additional SQL Server specific configuration.</param>
turric4n marked this conversation as resolved.
Show resolved Hide resolved
/// <param name="name">The health check name. Optional. If <c>null</c> the type name 'sqlserver' will be used for the name.</param>
turric4n marked this conversation as resolved.
Show resolved Hide resolved
sungam3r marked this conversation as resolved.
Show resolved Hide resolved
/// <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 AddMySql(
this IHealthChecksBuilder builder,
Func<IServiceProvider, string> connectionStringFactory,
string healthQuery = HEALTH_QUERY,
Action<MySqlConnection>? configure = null,
string? name = default,
HealthStatus? failureStatus = default,
IEnumerable<string>? tags = default,
TimeSpan? timeout = default)
{
Guard.ThrowIfNull(connectionStringFactory);

return builder.Add(new HealthCheckRegistration(
name ?? NAME,
sp =>
{
var options = new MySqlHealthCheckOptions
{
ConnectionString = connectionStringFactory(sp),
CommandText = healthQuery,
Configure = configure,
};
return new MySqlHealthCheck(options);
},
failureStatus,
tags,
timeout));
}

/// <summary>
/// Add a health check for MySQL/MariaDB Server databases.
/// </summary>
/// <param name="builder">The <see cref="IHealthChecksBuilder"/>.</param>
/// <param name="options">Options for health check.</param>
/// <param name="name">The health check name. Optional. If <c>null</c> the type name 'sqlserver' 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 AddMySql(
this IHealthChecksBuilder builder,
MySqlHealthCheckOptions options,
string? name = default,
HealthStatus? failureStatus = default,
IEnumerable<string>? tags = default,
TimeSpan? timeout = default)
{
Guard.ThrowIfNull(options);

return builder.Add(new HealthCheckRegistration(
name ?? NAME,
_ => new MySqlHealthCheck(connectionString),
_ => new MySqlHealthCheck(options),
failureStatus,
tags,
timeout));
Expand Down
24 changes: 19 additions & 5 deletions src/HealthChecks.MySql/MySqlHealthCheck.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,38 @@ namespace HealthChecks.MySql;
/// </summary>
public class MySqlHealthCheck : IHealthCheck
{
private readonly string _connectionString;
private readonly MySqlHealthCheckOptions _options;

public MySqlHealthCheck(string connectionString)
public MySqlHealthCheck(MySqlHealthCheckOptions options)
{
_connectionString = Guard.ThrowIfNull(connectionString);
Guard.ThrowIfNull(options.ConnectionString, true);
Guard.ThrowIfNull(options.CommandText, true);
_options = options;
}

/// <inheritdoc />
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
try
{
using var connection = new MySqlConnection(_connectionString);
using var connection = new MySqlConnection(_options.ConnectionString);
sungam3r marked this conversation as resolved.
Show resolved Hide resolved

await connection.OpenAsync(cancellationToken).ConfigureAwait(false);

using var command = connection.CreateCommand();

command.CommandText = _options.CommandText;

object? result = await command
.ExecuteScalarAsync(cancellationToken)
.ConfigureAwait(false);
sungam3r marked this conversation as resolved.
Show resolved Hide resolved

var returnQueryResults =
_options.HealthCheckResultBuilder?
.Invoke(result) ?? HealthCheckResult.Healthy();
sungam3r marked this conversation as resolved.
Show resolved Hide resolved

return await connection.PingAsync(cancellationToken).ConfigureAwait(false)
? HealthCheckResult.Healthy()
? returnQueryResults
: new HealthCheckResult(context.Registration.FailureStatus, description: $"The {nameof(MySqlHealthCheck)} check fail.");
}
catch (Exception ex)
Expand Down
31 changes: 31 additions & 0 deletions src/HealthChecks.MySql/MySqlHealthCheckOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using MySqlConnector;

namespace HealthChecks.MySql;

/// <summary>
/// Options for <see cref="MySqlHealthCheck"/>.
/// </summary>
public class MySqlHealthCheckOptions
turric4n marked this conversation as resolved.
Show resolved Hide resolved
{
/// <summary>
/// The MySQL Server connection string to be used.
sungam3r marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
public string ConnectionString { get; set; } = null!;

/// <summary>
/// The query to be executed.
/// </summary>
public string CommandText { get; set; } = MySqlHealthCheckBuilderExtensions.HEALTH_QUERY;

/// <summary>
/// An optional action executed before the connection is opened in the health check.
/// </summary>
public Action<MySqlConnection>? Configure { get; set; }

/// <summary>
/// An optional delegate to build health check result.
/// </summary>
public Func<object?, HealthCheckResult>? HealthCheckResultBuilder { get; set; }
}