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

ASP.NET Core启动时数据库异常如何终止Hangfire Server

解决Hangfire在数据库连接失败后持续重试的问题

我有一个基于ASP.NET Core的项目,使用Hangfire结合SQL Server存储处理定时任务。项目启动时会先检查数据库连接是否有效,如果数据库有问题,中间件会显示错误信息并终止应用。简化后的Program.cs代码如下:

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

// (Register other services)

builder.Services.AddHangfire(config =>
{
    config.SetDataCompatibilityLevel(CompatibilityLevel.Version_180);
    config.UseSimpleAssemblyNameTypeSerializer();
    config.UseRecommendedSerializerSettings();
    config.UseSqlServerStorage("connectionString");
});

WebApplication app = builder.Build();

using IServiceScope scope = app.Services.CreateScope();
IServiceProvider services = scope.ServiceProvider;

IDatabaseService database = services.GetRequiredService<IDatabaseService>();

// 数据库异常时设置标记
await database.EnsureInitializedAsync();

// 检查标记并返回错误响应,终止请求和进程
app.UseMiddleware<DatabaseInitializationMiddleware>();
app.MapDefaultControllerRoute();
app.Run();

添加Hangfire后,当数据库连接无效时,即便已经通过EnsureInitializedAsync()检测到问题,应用仍会每15秒重复抛出SqlException。我希望在数据库检测出问题后停止Hangfire,避免它持续尝试连接直到应用终止。

我曾尝试在数据库初始化检查后添加以下代码:

using BackgroundJobServer server = new BackgroundJobServer(JobStorage.Current);
server.SendStop();
await server.WaitForShutdownAsync(default);

但执行时出现错误:

System.InvalidOperationException: 'Current JobStorage instance has not been initialized yet.


问题原因

错误源于JobStorage.Current尚未完成初始化,Hangfire的配置和服务都是通过DI容器注册的,直接实例化BackgroundJobServer无法获取正确的配置上下文。

解决方案

方案一:按需注册Hangfire服务(推荐)

提前检查数据库状态,仅当数据库连接正常时才注册Hangfire相关服务,从根源避免无效重试:

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

// 构建临时服务容器检查数据库状态
using (var tempScope = builder.Services.BuildServiceProvider().CreateScope())
{
    var database = tempScope.ServiceProvider.GetRequiredService<IDatabaseService>();
    bool isDatabaseHealthy = await database.EnsureInitializedAsync();

    if (isDatabaseHealthy)
    {
        // 数据库正常才注册Hangfire
        builder.Services.AddHangfire(config =>
        {
            config.SetDataCompatibilityLevel(CompatibilityLevel.Version_180);
            config.UseSimpleAssemblyNameTypeSerializer();
            config.UseRecommendedSerializerSettings();
            config.UseSqlServerStorage("connectionString");
        });
        builder.Services.AddHangfireServer(); // 注册Hangfire服务端
    }
}

WebApplication app = builder.Build();

app.UseMiddleware<DatabaseInitializationMiddleware>();
app.MapDefaultControllerRoute();
app.Run();

方案二:数据库异常时主动停止Hangfire服务

如果必须提前注册Hangfire服务,可在数据库检查失败后从DI容器获取服务端实例并停止:

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

// 正常注册Hangfire服务
builder.Services.AddHangfire(config =>
{
    config.SetDataCompatibilityLevel(CompatibilityLevel.Version_180);
    config.UseSimpleAssemblyNameTypeSerializer();
    config.UseRecommendedSerializerSettings();
    config.UseSqlServerStorage("connectionString");
});
builder.Services.AddHangfireServer();

WebApplication app = builder.Build();

using IServiceScope scope = app.Services.CreateScope();
IServiceProvider services = scope.ServiceProvider;

IDatabaseService database = services.GetRequiredService<IDatabaseService>();
bool isDatabaseHealthy = await database.EnsureInitializedAsync();

if (!isDatabaseHealthy)
{
    // 获取Hangfire服务端并停止
    var hangfireServer = services.GetService<IBackgroundJobServer>();
    if (hangfireServer != null)
    {
        hangfireServer.SendStop();
        await hangfireServer.WaitForShutdownAsync(default);
    }
}

app.UseMiddleware<DatabaseInitializationMiddleware>();
app.MapDefaultControllerRoute();
app.Run();

说明

  • 方案一效率更高,数据库异常时不会初始化任何Hangfire资源,彻底避免了后续的重试逻辑。
  • 方案二适用于需要提前注册Hangfire服务的场景,通过主动停止服务端终止Hangfire的后台连接尝试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 22:29:53