RequestAdditionalTime() 的安全开销是多少?

What is a safe overhead for RequestAdditionalTime()?

我有一个 Windows 服务,它在单独的线程上生成一组子活动,并且只有在所有这些活动都成功完成时才应该终止。我事先不知道在收到停止信号后终止 activity 可能需要多长时间。在 OnStop() 期间,我每隔一段时间等待该停止信号,并一直请求额外的时间,只要系统愿意授予它即可。

基本结构如下:

class MyService : ServiceBase
{
    private CancellationTokenSource stopAllActivities;
    private CountdownEvent runningActivities;

    protected override void OnStart(string[] args)
    {
        // ... start a set of activities that signal runningActivities
        //       when they stop
        // ... initialize runningActivities to the number of activities
    }

    protected override void OnStop()
    {
        stopAllActivities.Cancel();

        while (!runningActivities.Wait(10000))
        {
            RequestAdditionalTime(15000); // NOTE: 5000 added for overhead
        }
    }
}

我应该在 RequestAdditionalTime 调用中添加多少 "overhead"?我担心请求是累积的,而不是基于每次 RequestAdditionalTime 调用的时间点。如果是这种情况,增加开销可能会导致系统最终拒绝请求,因为它在未来太遥远了。但是,如果我不增加任何开销,那么我的服务可能会在它有机会请求下一个额外时间块之前终止。

This post 并不十分令人鼓舞:

The MSDN documentation doesn’t mention this but it appears that the value specified in RequestAdditionalTime is not actually ‘additional’ time. Instead, it replaces the value in ServicesPipeTimeout. Worse still, any value greater than two minutes (120000 milliseconds) is ignored, i.e. capped at two minutes.

我希望情况并非如此,但我post将此作为最坏情况的答案。

更新: post 的作者非常友好 post 对我的评论进行了非常详细的回复,我已将其复制在下面。

Lars, the short answer is no.

What I would say is that I now realise that Windows Services ought to be designed to start and terminate processing quickly when requested to do so.

As developers, we tend to focus on the implementation of the processing and then package it up and deliver it as a Windows Service.

However, this really isn’t the correct approach to designing Windows Services. Services must be able to respond quickly to requests to start and stop not only when an administrator making the request from the services console but also when the operating system is requesting a start as part of its start up processing or a stop because it is shutting down,

Consider what happens when Windows is configured to shut down when a UPS signals that the power has failed. It’s not appropriate for the service to respond with “I need a few more minutes…”.

It’s possible to write services that react quickly to stop requests even when they implement long running processing tasks. Usually a long running process will consist of batch processing of data and the processing should check if a stop has been requested at the level of the smallest unit of work that ensures data consistency.

As an example, the first service where I found the stop timeout was a problem involved the processing of a notifications queue on a remote server. The processing retrieved a notification from the queue, calling a web service to retrieve data related to the subject of the notification, and then writing a data file for processing by another application.

I implemented the processing as a timer driven call to a single method. Once the method is called it doesn’t return until all the notifications in the queue have been processed. I realised this was a mistake for a Windows Service because occasionally there might be tens of thousands of notifications in the queue and processing might take several minutes.

The method is capable of processing 50 notifications per second. So, what I should have done was implement a check to see if a stop had been requested before processing each notification. This would have allowed the method to return when it has completed the processing of a notification but before it has started to process the next notification. This would have ensured that the service responds quickly to a stop request and any pending notifications remained queued for processing when the service is restarted.