Thursday, February 10, 2011

Dealing with Slow Starting Windows Services

Every once in a while a question pops up about Windows Installer trying to start a service and if fails but that if the user starts it manually it works. The solution usually turns out to be related to solving some race condition either in terms of dependency or timing. I won't attempt to enumerate all of these today but I did want to draw attention to something I recently observed.

The Windows (NT) Service Control Manager ( SCM ) waits up to 30 seconds by default for a service to report that a pending operation is successful. There is a registry value called ServicesPipeTimeout that can be used to change this behavior to a longer time. In doing so though one must keep the following in mind:

As with many things ServiceControlManager related, the ServicesPipeTimeout setting requires a reboot to become effective. It’ll offer no help if you are trying to start a service during the install.

Even if it was effective right away, I’ve observed that when the MSI SDK says “max 30 seconds” it means 30 seconds max. Changing the ServicesPipeTimeout setting has no effect on the behavior of the StartServices standard action. ( A bug in my opinion. MSI should track with SCM in my opinion. )

Now personally, I think it would be a mistake for an installer to set ServicesPipeTimeout. This is the sort of system wide setting that I usually shy away from out of fear of causing unforeseen side effects. However, I am interested in knowing if any of my readers have experience with this setting and how things turned out for them.

So in conclusion, a setting exists but it won't help with the installer much unless all you need to do is set the service to automatic and ask for a reboot.

For C#/.NET junkies using the ServiceBase class, I'll offer an additional observation that thread.Sleep() calls in the OnStart() method exceeding the ServicesPipeTimeout threshold didn't seem to cause any problems. However placing the delay in the constructor or instance members in the class did cause a problem.

8 comments:

Do you have examples of the kinds of service dependencies you've had problems with under this scenario? I'm curious as I haven't found any that I couldn't mitigate by setting the Dependencies and/or LoadOrderGroup attributes for the service in the ServiceInstall Table. Of course, the products I work with don't have a lot of dependencies on MS/3rd party services - I mainly have to deal with load order of our own services.

One publical example was a person on StackOverflow who was calling a webservice during the service startup in order to get some configuration data. For that user it could have been 'patched' by tweaking the Dependencies ( it failed on machine startup but worked manually later ) but it also could have failed later for other reasons. The better solution was to report back that the service was started and then in the other thread make the calls to get the configuration data and log accordingly (and/or create a monitoring pattern ) of the service status.

Actually ServiceBase does have a RequestAdditionalTime() method. Is this what you were talking about? I did play with this but I found that you could only call it in the OnStart method not the constructor and that either way Windows Installer didn't care. 30 seconds was the most MSI was going to give you.

Chris, I have an application that deploys a service that is written in C#. We have found, that in certain environments, we get a lengthy startup time if the service depends on DLLs with digital signatures. This is caused by a feature of .NET prior to 4.0 which attempts to verify the authenticode signature. In some environments, this takes especially long due to their network configuration.

The good news is, you can change this behavior if your service is written in .NET 3.5 by adding the following:

</configuration

This is documented at http://msdn.microsoft.com/en-us/library/bb629393(v=VS.90).aspx, and is now the default behavior in .NET 4.0.

That does look like the same thing but I was thinking of SetServiceStatus() from the underlying SCM API. It has been a while since I wrote a C++ service but in theory your code gets called regularly and you can request more time. When I last looked at a C# service I couldn't find and equivalent (.Net 2.0). The other thing I remember is the starting a service via the SCM UI is not the same as doing it via API calls. For example, I think you have to implemented dependencies yourself. So it wouldn't surprise me if the request more time wasn't always implemented.

In the end we changed the structure of our service so that the service code simply starts up a few threads. These threads then do the real work of starting up the service - in our case waiting for SQL server to come online.