我在使用C#创建的Windows服务中遇到了超时问题,无法确定原因。 我花了很多时间查看了几篇关于此问题的文章和主题,但不确定该尝试什么其他方法。
问题是什么?
有时,在某些运行我的Windows服务的机器上,在机器重启后,它无法成功启动。 我收到关于服务未能及时启动并在30000毫秒后超时的常见事件日志消息。 Windows Server 2003机器似乎是最常见的模式,但不总是局限于这个操作系统。例如,在其他W2K3机器上完全正常工作。
启动故障可能非常随机,有时会启动,有时会失败,因此非常难以按需复现该问题。 我还使用Log4Net捕获错误并将其记录到RollingFileAppender中。但是,当服务无法启动时,永远不会创建日志文件,也没有保存任何日志信息。 就好像我的服务入口线程正在阻塞并且未被调用。
其他详细信息:
- Windows服务是用C#编写的,并使用.Net 2.0。
- 安装时我的服务没有其他服务依赖项。
- 服务exe是一个没有签名或真实代码签名的发布版本。
- OnStart方法通过创建线程并启动该线程尽快执行。在OnStart中没有进行任何其他初始化。
- 当服务实际上无法启动时,手动打开服务列表并启动它每次都是有效的,并且服务将在不到一秒钟内启动。
我已经添加了以下代码到我的Program.cs中,其中包括服务的主入口点。 我挂接了一个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。 我只是在等待适当的停机时间来访问客户端服务器以测试这些内容。