我正在运行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中推出以防止出现错误,但我希望在启动后尽快运行它。
这可能吗?这是最好的方法吗?任何建议将不胜感激。
答案 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()
方法本身并未延迟。
根据需要随意添加任务取消,异常处理和其他细节。 :)