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_PRESHUTDOWN 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 , , , , , , | 13 Comments

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

  1. Firat says:

    Hi,
    Thanks for very usefull post.
    I need exactly this 3 minutest delay and I guided this post and build my service.
    But unfortunately windows is not waiting 3 minutes. I am logging the preshutdown process to text file with time stamp to see whats happening while shutdown, and i see from logs that windows gives my service 30 seconds. The system is : Windows Server 2012 R2
    Do you have any idea why ?

    Thanks

  2. Core Technologies Consulting says:

    Hi Firat. Are you calling the SetServiceStatus function and passing the SERVICE_ACCEPT_PRESHUTDOWN flag in the SERVICE_STATUS structure? If so, please ensure that the call succeeds by checking the return parameter.

    And is your service receiving and taking action on the SERVICE_CONTROL_PRESHUTDOWN notification?

    Please feel free to send us your code and we’ll have a look.

  3. Sumukh says:

    Hi ,
    I have the error message appearing for a service I have developed when I stop, not start. May be the service is starting in quick time than it takes to stop. The registry approach I have tried and works.

    But the concern for me is I do not want other less priority services get this ample time to block the SCM.
    Means the registry if we change to a higher value even the services with less priority block until they are completely stopped within the extra given time or this extra time has elapsed.

    I have tried PRESHUTDOWN notification approach where in I modified code accordingly as you said above but this did not work. Instead I was able to see the service taking considerably more time than the original before throwing the error.

    After OpenService() I have exactly as said above..
    This did not work

    Then I tried adding the mentioned code after CreateService() [Which is after OpenService], even this did not work.

    For info I am using C++ code.

    Please reply ASAP

  4. Hi Sumukh, sorry to hear of the trouble.

    Since you do not want to give every service additional time to stop, let’s focus on the preshutdown process. Please zip and email us the relevant parts of your code so that our development team can review.

  5. Sumukh says:

    I have emailed you the code parts and briefly explained.
    Please check and let me know if you need anything else.

    Regards
    Sumukh

  6. Thanks Sumukh. Let’s discuss over email.

  7. Zeya Myint says:

    Hi,

    I got the same problem as Firat (post on Sep 21st, 2019). It only give me 30 seconds. Not 3 minutes. My C# implementation is pretty much copied from the link you has mentioned in the article. I am running the service on Windows 2012 R2. Does 3 minutes timeout depend on OS version?

    Thanks,
    Zeya

  8. Hi Zeya.

    The timeout is not OS dependent.

    Can you please send your code to us? We’ll review and let you know if we find any errors.

  9. Zeya Myint says:

    const int SERVICE_ACCEPT_PRESHUTDOWN = 0x100;
    const int SERVICE_CONTROL_PRESHUTDOWN = 0xf;

    MyService
    {

    FieldInfo acceptedCommandsFieldInfo =
    typeof(ServiceBase).GetField(“acceptedCommands”, BindingFlags.Instance | BindingFlags.NonPublic);
    if (acceptedCommandsFieldInfo == null)
    throw ApplicationException(“acceptedCommands field not found”);

    int value = (int)acceptedCommandsFieldInfo.GetValue(this);
    acceptedCommandsFieldInfo.SetValue(this, value | SERVICE_ACCEPT_PRESHUTDOWN);
    }

    protected override void OnCustomCommand(int command)
    {
    if (command == SERVICE_CONTROL_PRESHUTDOWN)
    {
    for(int=0; i<60; i++)
    {
    Thread.Sleep(1000);
    Logger.log("sleeping one second. i=" + i);
    // This log is printed 30 times
    }

    // Clean up Data here
    }
    else
    base.OnCustomCommand(command);
    }

  10. Thanks.

    So you are receiving the SERVICE_CONTROL_PRESHUTDOWN notification, which is good. However it’s only waiting for 30 seconds, right?

    The documentation says that the default timeout is 180 seconds, but maybe that is different on your system.

    I suggest calling ChangeServiceConfig2 with the SERVICE_PRESHUTDOWN_INFO object setting the timeout value to 120. Do this in the same area where you register for the preshutdown notifications (i.e. at the start of your application).

  11. Zeya Myint says:

    Right. Only 30 seconds. Do you have C# example for ChangeServiceConfig2 call?

  12. Zeya Myint says:

    Thanks! I will update you if I can confirm a working solution.

Leave a Reply

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