C# Windows 服务启动超时

发布于 2024-11-28 17:50:34 字数 2666 浏览 1 评论 0原文

我在尝试确定使用 C# 创建的 Windows 服务超时的原因时遇到困难。 我花了相当多的时间查看有关该问题的几个帖子和主题,但我不确定还可以尝试什么。

问题是什么?

有时,在某些运行 Windows 服务的计算机上,重新启动计算机后它无法成功启动。 我收到有关服务无法及时启动并且在 30000 毫秒后超时的常见事件日志消息。 Windows Server 2003 计算机似乎是最常见的模式,但并不总是仅与该操作系统隔离。例如,它在其他 W2K3 机器上运行得非常好。

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

其他详细信息:

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

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

I'm having difficulty trying to determine the cause of a timeout in a Windows Service I've created with C#.
I've spent a considerable amount of time looking at several posts and topics on the issue but I am unsure what else to try.

What's the problem?

Sometimes on certain machines which run my windows service, it does not start successfully after the machine has been rebooted.
I receive the common EventLog messages about the Service failing to start in a timely fashion and that it timed out after 30000 milliseconds.
Windows Server 2003 machines seem to be the most common pattern but is not always isolated to just this OS. For example it works perfectly fine on other W2K3 machines.

The startup failure can be quite random in that sometimes it will start, and other times it will fail so it is very difficult to reproduce the issue on demand.
I am also using Log4Net to catch and errors and log them to a RollingFileAppender. However, when the service fails to start, no log file is ever created and no log information saved.
It is as if my Service entry thread is blocking and not getting called.

Other Details:

  1. The Windows service is written in C# and uses .Net 2.0
  2. There are no other service dependencies for my service when
    installed.
  3. The service exe is a Release build with no signing or authenticode
    signing.
  4. The OnStart method executes as quickly as possible by creating a
    Thread and starting that Thread. No other initialization takes place
    within OnStart.
  5. When the service does actually fail to start, opening the services
    list and starting it manually works every time and the service
    starts in probably less than a second.

I have the following code added to my Program.cs which include the main entry point for the service.
I hook in to an UnhandledException event on the CurrentDomain and am using log4net to log any unhandled errors
There's also a try/catch around the ServiceBase.Run in the event it somehow bombs out so that I can log that error.

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);
}

The code in my inherited ServiceBase implementation is as follows:

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>
}

My log4net implementation is using a ConsoleAppender and a RollingFileAppender where its configuration details are stored in the App.config.

At this stage I am not sure what else to try.
If any more details are needed let me know.

Thanks.

Update:
Just to update everyone, I'm going to try some of the suggestions such as logging to the EventLog directly or a file instead of Log4Net to see if that's the cause.
I Will also try setting the generatePublisherEvidence in the app.config to false.
I'm just waiting for an appropriate downtime to access the client's server to test these things out.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

演多会厌 2024-12-05 17:50:34

我通过关闭配置文件中的发布者证据生成解决了类似的问题。该服务也没有验证码签名,但添加以下行立即修复了一致再现的机器上的问题。

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

还推荐 此 MSDN 来源
“我们建议服务使用该元素来提高启动性能。使用该元素还可以帮助避免可能导致服务启动超时和取消的延迟。”

I fixed similar issue by turning off publisher evidence generation in config file. The service also did not have authenticode signing but adding following line immediately fixed the issue on the machine where it has been reproduced consistently.

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

Also recommended in this MSDN source:
"We recommend that services use the element to improve startup performance. Using this element can also help avoid delays that can cause a time-out and the cancellation of the service startup. "

皇甫轩 2024-12-05 17:50:34

一般来说,从 OnStart 生成后台线程是正确的做法。

为了进行故障排除,您可以尝试通过调用 来自 OnStart 的 RequestAdditionalTime 方法。另外,您可能想要检查是否有任何消息已写入 Windows 事件日志(日志“应用程序”,来源应该是您的服务名称)。

In general, spawning a background thread from OnStart is the right thing to do.

For troubleshooting purposes, you could try to give your service more startup time by calling RequestAdditionalTime method from OnStart. Also, you might want to check if any messages have been written to the Windows EventLog (log "Application", the source should be your service name).

感情废物 2024-12-05 17:50:34

需要尝试的一些事情:

  • 将日志消息添加到 Main() 的顶部、ServiceBase.Run() 之前,等等。假设您获得一个日志文件,这些时间戳与 Windows 事件日志相比如何?

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

  • 获取进程监视器并观察正常启动情况。查找任何意外的网络或文件 I/O。

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

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

A few things to try:

  • Add log messages to the top of Main(), before ServiceBase.Run(), etc. Assuming you get a log file, how do those timestamps compare to the Windows Event Log?

  • Create a brand new Service with the New Project Wizard and deploy it as-is. On the problem machines, does it start reliably?

  • Get process monitor and watch a normal startup. Look for any unexpected network or file I/O.

  • Make sure your SchedulerService does not do any work in the constructor, and does not have any statically-initialized dependencies.

  • Set the Recovery options to restart on first failure. Does that work reliably?

笑忘罢 2024-12-05 17:50:34

我还怀疑 log4net 不知何故挂起。机器启动时,可能要创建日志的驱动器尚未准备好。您是否尝试过延迟启动服务?

在此处输入图像描述

I'd also suspect that log4net is somehow hanging. Maybe the drive where the log is to be created is not ready yet when the machine is booting. Have you tried starting your service delayed?

enter image description here

梦晓ヶ微光ヅ倾城 2024-12-05 17:50:34

Since log4net is not designed to be (in their words) a reliable logging system, I thought it was good practice to write unhandled exceptions to the eventlog (as well as to your log), especially with services.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文