Windows 服务没有及时启动 - 将初始工作量传递给计时器?

Windows Service not starting in a timely manner - pass off initial workload to timer?

我正在 运行 宁 Windows 服务执行大型数据迁移过程(第一次 运行 需要 10 分钟以上)。目前我有服务 运行ning 最初在启动时一次,然后每 4 小时一次。像这样(摘录):

protected override void OnStart(string[] args)
{
    // Set up timer
    int intervalSync = 14400; // 4 hours default
    timer = new System.Timers.Timer();
    timer.Interval = intervalSync * 1000;
    timer.Elapsed += new System.Timers.ElapsedEventHandler(this.OnTimer);
    timer.Start();

    // Call once initially.
    this.DoMigration();
}

public void OnTimer(object sender, System.Timers.ElapsedEventArgs args)
{
    this.DoMigration();
}

问题是在部署和 运行ning 之后,Windows 服务错误 "The service did not respond to the start or control request in a timely fashion"。

我意识到我可以只从 OnStart 中删除对 DoMigration() 的初始调用,并让服务快速启动 - 但是工作将在 4 小时内无法完成,这是不可取的。

有没有办法可以将第一个计时器的时间间隔设置为 运行(可能是 30 秒或 60 秒),然后再设置单独的 4 小时周期性间隔?基本上我想将工作负载推出 OnStart 以防止错误,但我仍然希望在启动后尽快拥有它 运行。

这可能吗?这是最好的方法吗?如有任何建议,我们将不胜感激。

问题是 OnStart 方法需要在相当短的时间内完成(也许是 30 秒?),然后 Windows 才会认为出现问题。一个简单的解决方案是在第一个 运行 时非常快速地触发计时器,然后在 4 小时内再次将计时器从事件内部重新配置为 运行:

protected override void OnStart(string[] args)
{
    // Set up timer
    int initialIntervalSync = 10; // 10 seconds
    timer = new System.Timers.Timer();
    timer.Interval = initialIntervalSync * 1000;
    timer.Elapsed += new System.Timers.ElapsedEventHandler(this.OnTimer);
    timer.Start();    
}

public void OnTimer(object sender, System.Timers.ElapsedEventArgs args)
{
    //Reset timer interval
    int intervalSync = 14400; // 4 hours default
    timer.Interval = intervalSync * 1000;

    this.DoMigration();
}

恕我直言,解决此问题的最简单方法是使用 async/await:

protected override void OnStart(string[] args)
{
    // Storing the returned Task in a variable is a hack
    // to suppresses the usual compiler warning.
    var _ = DoMigrationLoop();
}

private async Task DoMigrationLoop()
{
    while (true)
    {
        await Task.Run(() => this.DoMigration());
        await Task.Delay(TimeSpan.FromHours(4));
    }
}

这会导致 DoMigration() 方法立即在单独的线程中执行,此后每四个小时执行一次。请注意,由于原始 DoMigrationLoop() 方法在第一次 await 调用时立即调用 returns,因此 OnStart() 方法本身根本没有延迟。

随意添加任务取消、异常处理和其他需要的细节。 :)