Windows服务无法及时启动 - 将初始工作负载转移到计时器?

时间:2015-10-28 23:56:43

标签: c# .net service timer windows-services

我正在运行Windows服务,该服务执行大型数据迁移过程(首次运行需要10分钟+)。目前我的服务最初在启动时运行一次,然后每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();
}

问题是在部署和运行之后,Windows服务错误“服务没有及时响应启动或控制请求”。

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

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

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

2 个答案:

答案 0 :(得分:1)

问题是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();
}

答案 1 :(得分:1)

恕我直言,解决此问题的最简单方法是使用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调用时立即返回,因此OnStart()方法本身并未延迟。

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