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

Windows服务循环重试启动报错及停止异常问题咨询

Windows服务数据库连接失败后自动重试的问题与解决方法

问题场景

开发的Windows服务依赖数据库连接,当数据库不可用时服务会抛出异常并停止。希望实现服务循环尝试连接直至成功,但当前代码运行后出现以下问题:

  1. 首次启动因数据库不可用报错,等待30秒重试时提示Service cannot be started. An instance of the service is already running.
  2. 手动停止服务时崩溃,抛出无法访问已释放的对象。对象名称: 'EventLogInternal'异常

用户原代码如下:

public class Program
{
    public static void Main(string[] args)
    {
        var appConfigurationManager = new AppConfigurationManager();
        bool startupSuccessful = false;

        do
        {
            using (var host = CreateHostBuilder(args, appConfigurationManager).Build())
            try
            {

                host.Run();
                startupSuccessful = true;
            }
            catch (Exception ex)
            {
                Thread.Sleep(TimeSpan.FromSeconds(30));
            }
        }
        while (!startupSuccessful);
    }

    public static IHostBuilder CreateHostBuilder(string[] args, IAppConfigurationManager appConfigurationManager)
    {
        return Host.CreateDefaultBuilder(args)
            .UseWindowsService(options =>
            {
                options.ServiceName = $"MyServiceName";
            })
            .ConfigureServices((context, services) =>
            {
                // 省略其他服务注册
                services.AddHostedService<SomeBackgroundService>();
                // 省略其他服务注册
            });
    }
}

问题根源

  1. 服务状态冲突:Windows服务控制管理器会跟踪服务运行状态,首次host.Run()抛出异常后,管理器可能已标记服务为启动状态,再次创建并运行Host会触发"服务已运行"的冲突。
  2. 资源释放异常:using语句会释放Host实例,其中包含的EventLog日志组件也会被销毁。手动停止服务时,Windows服务生命周期尝试写入日志,就会访问已释放的EventLogInternal对象,导致ObjectDisposedException。

正确实现方案

方案一:后台服务内部处理重试

将数据库连接及业务逻辑的重试逻辑放在SomeBackgroundService内部,保持Host始终运行,避免重启Host带来的状态冲突和资源问题。

示例代码:

public class SomeBackgroundService : BackgroundService
{
    private readonly ILogger<SomeBackgroundService> _logger;
    private readonly IDbConnectionFactory _dbConnectionFactory;

    public SomeBackgroundService(ILogger<SomeBackgroundService> logger, IDbConnectionFactory dbConnectionFactory)
    {
        _logger = logger;
        _dbConnectionFactory = dbConnectionFactory;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                // 尝试连接数据库
                using var connection = await _dbConnectionFactory.CreateConnectionAsync(stoppingToken);
                await connection.OpenAsync(stoppingToken);
                _logger.LogInformation("数据库连接成功,执行业务逻辑");

                // 执行核心业务逻辑
                await RunBusinessLogic(connection, stoppingToken);

                // 业务逻辑执行完成后,按需设置等待间隔
                await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "数据库连接或业务逻辑失败,30秒后重试");
                await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
            }
        }
    }

    private async Task RunBusinessLogic(IDbConnection connection, CancellationToken stoppingToken)
    {
        // 替换为你的业务逻辑实现
    }
}

方案二:Host启动前完成连接重试

如果要求Host启动前必须确保数据库可用,可以在Host构建完成后、启动前添加连接重试逻辑,避免重启整个Host。

示例代码:

public class Program
{
    public static async Task Main(string[] args)
    {
        var appConfigurationManager = new AppConfigurationManager();
        var host = CreateHostBuilder(args, appConfigurationManager).Build();

        // 启动前先确保数据库连接成功
        using (var scope = host.Services.CreateScope())
        {
            var services = scope.ServiceProvider;
            var logger = services.GetRequiredService<ILogger<Program>>();
            var dbConnectionFactory = services.GetRequiredService<IDbConnectionFactory>();

            while (true)
            {
                try
                {
                    using var connection = await dbConnectionFactory.CreateConnectionAsync(CancellationToken.None);
                    await connection.OpenAsync(CancellationToken.None);
                    logger.LogInformation("数据库连接成功,启动服务");
                    break;
                }
                catch (Exception ex)
                {
                    logger.LogError(ex, "数据库连接失败,30秒后重试");
                    await Task.Delay(TimeSpan.FromSeconds(30));
                }
            }
        }

        await host.RunAsync();
    }

    public static IHostBuilder CreateHostBuilder(string[] args, IAppConfigurationManager appConfigurationManager)
    {
        return Host.CreateDefaultBuilder(args)
            .UseWindowsService(options =>
            {
                options.ServiceName = "MyServiceName";
            })
            .ConfigureServices((context, services) =>
            {
                services.AddSingleton<IDbConnectionFactory, YourDbConnectionFactory>();
                services.AddHostedService<SomeBackgroundService>();
                // 省略其他服务注册
            });
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 15:27:16