我在使用C#创建的Windows服务中尝试确定超时的原因时遇到了困难。 我花了相当多的时间查看有关该问题的几个帖子和主题,但我不确定还有什么可以尝试。
有什么问题?
有时在运行我的Windows服务的某些计算机上,重新启动计算机后它无法成功启动。 我收到有关服务无法及时启动的常见EventLog消息,并且在30000毫秒后超时。 Windows Server 2003计算机似乎是最常见的模式,但并不总是与此操作系统隔离。例如,它在其他W2K3机器上运行得非常好。
启动失败可能是非常随机的,因为它有时会启动,有时它会失败,因此很难按需重现问题。 我也使用Log4Net捕获和错误并将它们记录到RollingFileAppender。但是,当服务无法启动时,不会创建任何日志文件,也不会保存日志信息。 就好像我的服务条目线程阻塞而没有被调用。
其他详细信息:
我在Program.cs中添加了以下代码,其中包括服务的主要入口点。 我挂钩到CurrentDomain上的UnhandledException事件,并使用log4net记录任何未处理的错误 ServiceBase.Run中还有一个try / catch,如果它以某种方式炸弹,以便我可以记录该错误。
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new SchedulerService()
};
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
try
{
ServiceBase.Run(ServicesToRun);
}
catch (Exception ex)
{
Log.Fatal("Unhandled Service Exception", ex);
}
}
private static log4net.ILog _log = null;
static log4net.ILog Log
{
get
{
if (_log == null)
{
if (!log4net.LogManager.GetRepository().Configured)
{
log4net.Config.XmlConfigurator.Configure();
}
_log = log4net.LogManager.GetLogger(typeof(Program));
}
return _log;
}
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = e.ExceptionObject as Exception;
if (ex == null) ex = new Exception(e.ExceptionObject.ToString());
Log.Fatal("Unhandled Service Exception", ex);
}
我继承的ServiceBase实现中的代码如下:
protected override void OnStart(string[] args)
{
Thread serviceThread = new Thread(new ThreadStart(BackgroundStart));
serviceThread.IsBackground = true;
serviceThread.Start();
}
private void BackgroundStart()
{
//Initialize and start worker objects to perform monitoring...
//<Snip>
}
我的log4net实现正在使用ConsoleAppender和RollingFileAppender,其配置详细信息存储在App.config中。
在这个阶段,我不确定还有什么可以尝试的。 如果需要更多细节,请告诉我。
感谢。
更新 只是为了更新所有人,我将尝试一些建议,例如直接登录EventLog或文件而不是Log4Net,看看是否是原因。 我还会尝试将app.config中的generatePublisherEvidence设置为false。 我只是在等待适当的停机时间来访问客户端的服务器来测试这些东西。
答案 0 :(得分:7)
我通过在配置文件中关闭发布者证据生成来修复类似问题。该服务也没有authenticode签名,但添加以下行立即修复了机器上已经一致再现的问题。
<runtime>
<generatePublisherEvidence enabled="false" />
</runtime>
在this MSDN source中也建议:
“我们建议服务使用该元素来提高启动性能。使用此元素还可以帮助避免可能导致超时和取消服务启动的延迟。”
答案 1 :(得分:2)
要尝试的一些事项:
在Main()
等之前将日志消息添加到ServiceBase.Run()
的顶部。假设您获得了一个日志文件,那么这些时间戳与Windows事件日志相比如何?
使用“新建项目向导”创建全新服务并按原样部署。在问题机器上,它是否可靠地启动?
获取process monitor并观看正常启动。查找任何意外的网络或文件I / O.
确保您的SchedulerService
在构造函数中没有做任何工作,并且没有任何静态初始化的依赖项。
将恢复选项设置为在第一次失败时重新启动。这样可靠吗?
答案 2 :(得分:1)
通常,从OnStart
生成后台主题是正确的做法。
出于问题排查目的,您可以尝试从OnStart
调用RequestAdditionalTime方法,为您的服务提供更长的启动时间。此外,您可能想要检查是否有任何消息已写入Windows EventLog(日志“应用程序”,源应该是您的服务名称)。
答案 3 :(得分:1)
我还怀疑log4net是以某种方式悬挂的。当机器启动时,可能还没有准备好创建日志的驱动器。您是否尝试过延迟服务?
答案 4 :(得分:0)
由于log4net不是(in their words)一个可靠的日志记录系统,我认为将未处理的异常写入事件日志(以及日志)是一种好习惯,特别是对于服务。