The Core Technologies Blog

Our Software // Windows Services // 24×7 Operation


Q&A: How Do I Give my Windows Service More Time to Stop During Shutdown?

Q&A - Increase Service Timeout
  One of our file ingestion services can take a while to finish all pending database updates and exit cleanly. Sometimes when we reboot the server, Windows doesn’t wait for the service to finish, and we end up with database corruption, which is a huge pain.

How do I get Windows to wait until my service is done and not kill it while it’s still working?

— Jeff

Hi Jeff, sorry to hear of the database corruption!

For obvious reasons, Windows tries to shut itself down as quickly as possible. The goal is to complete the process in 20 seconds or less.

Applications and services that don’t respond within that time frame are classified as hung and are promptly terminated. As you have seen, this can lead to undesirable results.

Clearly this bias towards a quick shutdown makes sense for a desktop computer because a person is likely waiting patiently at the keyboard and mouse. However, it not ideal for servers running important background processes. In the server scenario, where interactive user experience is less of an issue, a safe shutdown should take precedence over a speedy one!

Fortunately there are a couple of ways to swing the balance of power to your Windows Service:

1. Extend the “Shutdown Timeout” for all Windows Services

As far as services are concerned, Windows follows this procedure when shutting down:

  1. Windows informs each service that it should shut down

  2. Windows waits until either:
    • all services have stopped, or
    • a fixed period has elapsed.
  3. Windows forcibly terminates any services still running

By default, that “fixed period” is only 5 seconds — insufficient time for your busy service to wind down gracefully.

Fortunately we can extend that period by modifying this registry value:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\WaitToKillServiceTimeout

How long does your service need to exit gracefully? Will 60 seconds be enough?

To change the timeout:

  1. Start the registry editor (“regedit”)

  2. In the tree on the left, navigate to:

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control

  3. In the right panel, find the WaitToKillServiceTimeout value. If you don’t see it, create it by:

    1. Selecting Control on the left

    2. Choosing Edit > New > String Value (not DWORD) from the menu

    3. Naming the new value WaitToKillServiceTimeout.

    WaitToKillServiceTimeout registry value
  4. Double-click the WaitToKillServiceTimeout entry to bring up the Edit String window. Enter 60000 in the Value data field (it’s in milliseconds) and click OK to save your change.

    Change WaitToKillServiceTimeout
  5. Reboot your computer. You don’t have to do that right now, but the new timeout setting will not take effect until Windows restarts.

Note that this modification will not make Windows wait indefinitely for your service to finish. If your service takes longer than 60 seconds, it will still be terminated. Be sure to choose a timeout value that is long enough to cover your scenario, but not too long to make shutdown intolerable.

2. Update your Windows Service to accept Preshutdown Notifications

Changing the WaitToKillServiceTimeout setting is a quick fix but the delay you specify will apply to all services. If another, non-critical service is hung, Windows will wait the full duration before terminating it.

To make sure that Windows waits for your specific service, you should update the code to accept preshutdown notifications.

Specifically, your service must:

  1. Call the SetServiceStatus function, passing the SERVICE_ACCEPT_PRESHUTDOWN flag in the SERVICE_STATUS structure;

  2. Clean up and exit when it receives the SERVICE_CONTROL_SHUTDOWN notification.

This article reviews the code to be added in C# projects.

How preshutdown works

The preshutdown process was introduced in Windows Vista (circa 2007). As the name suggests, it runs before the regular shutdown process. Its purpose is to give mission-critical services an early start on exiting, ahead of less important modules.

The preshutdown process looks like this:

  1. Windows notifies all services that have registered for preshutdown notifications to exit

  2. For each of those services, Windows waits until either:
    • the service has stopped, or
    • a fixed period has elapsed.
  3. Windows proceeds with the regular shutdown procedure (see above)

By default, that fixed period is 180 seconds (3 minutes) — more than enough time for most Windows Services to tidy up and exit gracefully.

But what if you need more than three minutes? Fortunately Microsoft has provided a solution there as well…

How to extend the preshutdown timeout beyond 3 minutes

With a simple code change, a preshutdown service can instruct Windows to wait more than the default 3 minutes for the service to end in the preshutdown phase.

You must add code to call the ChangeServiceConfig2 function with the SERVICE_CONFIG_PRESHUTDOWN_INFO level, and the timeout value in the SERVICE_PRESHUTDOWN_INFO structure set to an appropriate value.

Here is what the addition looks like in C++ (error checking omitted for brevity):

   SC_HANDLE hService =	OpenService(...);
   ...
   SERVICE_PRESHUTDOWN_INFO info;
   info.dwPreshutdownTimeout = 5 * 60 * 1000; // 5 minutes
   ChangeServiceConfig2(hService, SERVICE_CONFIG_PRESHUTDOWN_INFO, &info);

The new code is best called once when you install/setup your service, but it can be invoked during normal operation as well. Whichever works better in your situation.

Hopefully one of these two solutions will delay shutdown long enough to eliminate the database corruption. Please try them, and be sure to get in touch if you have any questions!

Posted in Windows Services | Tagged , , , , , , | Leave a comment

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>