C# Windows服务启动超时

17

我在使用C#创建的Windows服务中遇到了超时问题,无法确定原因。 我花了很多时间查看了几篇关于此问题的文章和主题,但不确定该尝试什么其他方法。

问题是什么?

有时,在某些运行我的Windows服务的机器上,在机器重启后,它无法成功启动。 我收到关于服务未能及时启动并在30000毫秒后超时的常见事件日志消息。 Windows Server 2003机器似乎是最常见的模式,但不总是局限于这个操作系统。例如,在其他W2K3机器上完全正常工作。

启动故障可能非常随机,有时会启动,有时会失败,因此非常难以按需复现该问题。 我还使用Log4Net捕获错误并将其记录到RollingFileAppender中。但是,当服务无法启动时,永远不会创建日志文件,也没有保存任何日志信息。 就好像我的服务入口线程正在阻塞并且未被调用。

其他详细信息:

  1. Windows服务是用C#编写的,并使用.Net 2.0。
  2. 安装时我的服务没有其他服务依赖项。
  3. 服务exe是一个没有签名或真实代码签名的发布版本。
  4. OnStart方法通过创建线程并启动该线程尽快执行。在OnStart中没有进行任何其他初始化。
  5. 当服务实际上无法启动时,手动打开服务列表并启动它每次都是有效的,并且服务将在不到一秒钟内启动。

我已经添加了以下代码到我的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。 我只是在等待适当的停机时间来访问客户端服务器以测试这些内容。


你尝试过在你的代码中添加调试语句来了解服务启动的进度吗? - Sebastian Piu
你也可以尝试启用log4net内部调试,以获取更多信息:http://logging.apache.org/log4net/release/faq.html#How%20do%20I%20enable%20log4net%20internal%20debugging%3F - Ronald Wildenberg
2
有可能是您的日志框架出现了问题,这可能会隐藏真正的问题,特别是当它挂起时您说没有任何日志记录。 - alun
1
log4net的初始化不是线程安全的,这就是我看到的问题。请在Main()中创建它。 - Hans Passant
1
你对此有结论了吗?我在我的一台机器上也遇到了同样的问题。没有日志,只是超时。 - Julius
显示剩余2条评论
5个回答

7

我通过在配置文件中关闭发布者证据生成来解决了类似问题。该服务也没有Authenticode签名,但添加以下行立即解决了在一台机器上始终重现的问题。

<runtime>
    <generatePublisherEvidence enabled="false" />
</runtime>

这个来自MSDN的文章中也有类似的建议:
"我们建议使用元素以提高服务启动性能,同时可以帮助避免延迟导致的超时和服务启动取消。"


2

通常情况下,从OnStart中生成一个后台线程是正确的做法。

为了排除故障,您可以尝试通过从OnStart调用RequestAdditionalTime方法来为服务提供更多的启动时间。此外,您可能需要检查是否有任何消息写入Windows事件日志(日志“应用程序”,源应该是您的服务名称)。


2

以下是一些尝试的方法:

  • Main()之前,在ServiceBase.Run()之前添加日志消息等。假设您获得了日志文件,那么这些时间戳与Windows事件日志相比如何?

  • 使用新项目向导创建全新的服务,并将其按原样部署。在有问题的计算机上,它是否能够可靠地启动?

  • 获取process monitor并观察正常启动。查找任何意外的网络或文件I/O。

  • 确保您的SchedulerService不会在构造函数中执行任何工作,并且没有任何静态初始化依赖项。

  • 将恢复选项设置为在第一次失败时重新启动。这样可靠吗?


1
我还怀疑log4net出现了问题。也许在机器启动时,创建日志的驱动器尚未准备好。您是否尝试过延迟启动服务?

enter image description here


抱歉,刚刚发现这个选项只适用于Vista及更高版本。但是您可能希望将记录器的创建移动到Main方法中,并延迟服务启动,直到记录器成功创建。 - Dirk Vollmar

0

由于log4net并非旨在成为(按照他们的说法)可靠的日志记录系统,因此我认为将未处理的异常写入事件日志(以及您的日志)是一个好的实践,特别是对于服务。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接