Topshelf在我们的应用程序中充当Windows Service Broker。今天早上,我们发现Stop方法被多次调用。这是相关的代码。
class Program
{
static void Main(string[] args)
{
ILog Log = new FileLog();
try
{
HostFactory.Run(serviceConfig =>
{
serviceConfig.Service<ServiceManager>(serviceInstance =>
{
serviceInstance.ConstructUsing(() => new ServiceManager());
serviceInstance.WhenStarted(execute => execute.Start());
serviceInstance.WhenStopped(execute => execute.Stop());
});
});
}
catch (Exception ex)
{
Console.WriteLine(ex);
Log.Error("Program.Main", ex, LogType.Error);
Console.ReadLine();
};
}
}
在ServiceManager中,我们具有Stop方法,它将被调用,然后TopShelf从操作系统接收停止信号。
class ServiceManager
{
xxx.....
public bool Stop()
{
try
{
_log.Info("The service is stopping", LogType.Info);
_service.StopExecuteProduceMessage();
Task.WaitAll(_tasks.ToArray());
_log.Info("The service is stopped", LogType.Info);
}
catch (Exception ex)
{
_log.Error("Stop", ex, LogType.Error);
}
return true;
}
}
今天早上,我们发现服务因不清楚的原因而停止。而且有许多行记录了此停止操作。
我猜想Topshelf会多次调用ServiceManager.Stop方法。有人遇到过这个问题吗?我想知道我可以追踪为什么发生这种情况。
任何人都可以帮忙吗?非常感谢。
答案 0 :(得分:1)
您遇到此现象的原因是您的Stop()方法需要一段时间,但没有响应停止请求。
您的方法本质上是这样的:
Stop() {
log-stopping;
wait-a-while;
log-stopped;
}
在等待时,服务的状态仍为“正在运行”。这导致请求者(可能是Windows本身或其他程序)继续重新发送停止请求,从而导致对Stop()的多个并行/重叠调用。这占了您包含的日志的前10行。
您可以看到“等待”完成大约需要20秒(从05:39:45到05:40:04)。
在那之后,看来Topshelf可能会卡住。这导致发送更多消息。 (请注意,在日志的下一行中,停止对和开始对同时记录,因为您的任务已停止并且没有等待时间。)
要解决此问题,您应该:
修改您的WhenStopped()调用,以将HostControl参数传递给Stop():
serviceInstance.WhenStopped((execute,hostControl)=> execute.Stop(hostControl));
更新Stop()方法以使用HostControl参数,并在调用Task.WaitAll()之前进行此调用:
hostControl.RequestAdditionalTime(TimeSpan.FromSeconds(30));
这将通知Windows您的服务已收到该请求,并且可能正在处理该请求长达30秒钟。那应该避免重复通话。