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. )
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.
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.
ReplyDeleteI do but many of the examples venture into the land of confidential.
ReplyDeleteOne 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.
If a service needs longer to start it should be written to call the SCM interface to tell it that it requires more time. Unfortunately this rarely happens and .Net doesn't even exposes the interface!
ReplyDeleteActually 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.
ReplyDeleteChris, 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.
ReplyDeleteThe 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.
Sorry, the comment block appears to have been munged. Just check out the MSDN link for the correct XML to add to your config file.
ReplyDeleteThat 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.
ReplyDeleteIn 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.
With ServicesPipeTimeout you will set it globally.
ReplyDeleteBetter set the dwWaitHint from the desired (slow) service to what you need with a CA.