You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 7健康检查重复执行:如何实现单次执行兼顾存储与通知

问题解决:避免健康检查重复执行,同时实现结果持久化与故障邮件通知

问题分析

当前配置存在两个独立的定时触发逻辑,导致健康检查重复执行且功能割裂:

  • HealthCheckPublisherOptions.Period:.NET内置的健康检查定时任务,会重复执行检查并调用CustomHealthCheckPublisher.PublishAsync,但不会将结果持久化到PostgreSQL
  • HealthChecksUI.SetEvaluationTimeInSeconds:HealthChecksUI的定时任务,会调用健康检查端点并将结果存入数据库,但不会触发自定义邮件通知

解决方案

核心思路是禁用.NET内置的健康检查定时任务,完全依托HealthChecksUI的定时机制执行检查并持久化结果,同时在UI执行完检查后触发自定义邮件通知逻辑。

具体步骤

  1. 移除内置定时配置:删除HealthCheckPublisherOptions的Period设置,避免内置定时触发重复检查
  2. 绑定UI执行回调:在HealthChecksUI的配置中添加OnHealthCheckExecuted回调,每次UI完成检查并持久化结果后,调用CustomHealthCheckPublisher.PublishAsync发送故障邮件

修改后的代码

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddHealthChecks()
        .AddCheck<NotificationsServiceHealthCheck>("Notifications service health check", tags: new[] { "external-service" });

    // 移除内置健康检查定时配置,避免重复执行
    // services.Configure<HealthCheckPublisherOptions>(options =>
    // {
    //     options.Period = TimeSpan.FromSeconds(evaluationTimeInSeconds);
    // });

    services.AddSingleton<IHealthCheckPublisher, CustomHealthCheckPublisher>();

    var evaluationTimeInSeconds = 60;
    services
        .AddHealthChecksUI(setup =>
        {
            setup.AddHealthCheckEndpoint("External services health checks", "https://localhost:44366/health-external-services");
            setup.SetEvaluationTimeInSeconds(evaluationTimeInSeconds);
            // 添加UI执行完成后的回调,触发邮件通知
            setup.OnHealthCheckExecuted(async (context) =>
            {
                var publisher = context.ServiceProvider.GetRequiredService<CustomHealthCheckPublisher>();
                await publisher.PublishAsync(context.Report, context.CancellationToken);
            });
        })
        .AddPostgreSqlStorage("CONNECTION_STRING", c => c.UseNpgsql(o => o.MigrationsHistoryTable(HistoryRepository.DefaultTableName, "hangfire")));
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
{
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapHealthChecks("/health-external-services", new HealthCheckOptions()
        {
            Predicate = r => r.Tags.Contains("external-service"),
            ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
        });
        
        endpoints.MapHealthChecksUI(setup =>
        {
            setup.UIPath = "/HealthChecks";
            setup.AsideMenuOpened = false;
        });
    });
}

CustomHealthCheckPublisher.cs(无需修改)

public class CustomHealthCheckPublisher : IHealthCheckPublisher
{
    public Task PublishAsync(HealthReport report, CancellationToken cancellationToken)
    {
        if (report.Status == HealthStatus.Healthy)
        {
            return Task.CompletedTask;
        }

        var nonhealthyChecks = report.Entries
            .Where(x => x.Value.Status != HealthStatus.Healthy)
            .ToList();

        // 发送包含nonhealthyChecks的故障邮件

        return Task.CompletedTask;
    }
}

效果说明

  • 健康检查仅由HealthChecksUI的定时任务触发,每60秒执行一次
  • 检查结果自动持久化到PostgreSQL
  • 每次检查完成后,自动调用CustomHealthCheckPublisher.PublishAsync,仅当检查状态为非健康时发送邮件通知

内容的提问来源于stack exchange,提问作者Aleks Vujic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 04:00:58