Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Windows Service Timeout on startup

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.

like image 758
Apocwhen Avatar asked Aug 10 '11 11:08

Apocwhen


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr.

Is C language easy?

C is a general-purpose language that most programmers learn before moving on to more complex languages. From Unix and Windows to Tic Tac Toe and Photoshop, several of the most commonly used applications today have been built on C. It is easy to learn because: A simple syntax with only 32 keywords.

Is C programming hard?

C is more difficult to learn than JavaScript, but it's a valuable skill to have because most programming languages are actually implemented in C. This is because C is a “machine-level” language. So learning it will teach you how a computer works and will actually make learning new languages in the future easier.


2 Answers

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. "

like image 70
Dmitry Avatar answered Oct 11 '22 03:10

Dmitry


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).

like image 31
Christian.K Avatar answered Oct 11 '22 02:10

Christian.K