【问题标题】:How to choose value for serviceStatus.dwWaitHint?如何为 serviceStatus.dwWaitHint 选择值?
【发布时间】:2016-07-20 19:16:52
【问题描述】:

我正在关注本教程:http://msdn.microsoft.com/en-us/library/zt39148a(v=vs.110).aspx 来创建 Windows 服务。我有一个名为TaskManager 的类,它使用 Quartz.Net 来管理一堆工作。它有.Go()(不会阻塞)和.Stop() 方法。如果我理解正确的话,在我的服务中我需要做的就是

    private TaskManager _taskManager;

    public DataPumpService()
    {
        InitializeComponent();
        _taskManager = new TaskManager();
    }

    protected override void OnStart(string[] args)
    {
        _taskManager.Go();
    }

    protected override void OnStop()
    {
        _taskManager.Stop();
    }

但是本教程有一个关于设置服务状态的部分。它并没有真正解释服务状态是什么,或者我什么时候想要设置它。 TaskManager.Stop() 可能需要几秒钟才能完成(在内部,它对所有作业调用 IScheduler.Interrupt(),然后调用 IScheduler.Shutdown(true))。那么我应该设置状态吗?如果是这样,那么假设我在the tutorial 的设置服务状态部分的第 (1)、(2) 和 (3) 部分中包含代码,那么执行以下操作是否正确(基本上对于我上面的第一个代码块中的两种方法) ):

    protected override void OnStop()
    {
        // Update the service state to Stop Pending.
        ServiceStatus serviceStatus = new ServiceStatus();
        serviceStatus.dwCurrentState = ServiceState.SERVICE_STOP_PENDING;
        serviceStatus.dwWaitHint = 100000;
        SetServiceStatus(this.ServiceHandle, ref serviceStatus);

        _taskManager.Stop();

        // Update the service state to Running.
        serviceStatus.dwCurrentState = ServiceState.SERVICE_STOPPED;
        SetServiceStatus(this.ServiceHandle, ref serviceStatus);
    }

如果这是正确的,那么 serviceStatus.dwWaitHint = 100000; 属性是我需要明智地选择还是坚持使用默认值?基本上我不知道这个值是什么......

【问题讨论】:

  • 嗯,不知道它是如何进入 MSDN 文章的。在 99.9% 的情况下,ServiceBase 类已经处理服务状态的方式已经足够好了。包括这个dwWaitHint,它被ServiceBase.RequestAdditionalTime()方法包裹。您不需要它,30 秒足以启动 99.9% 的所有服务 :) 请注意,本文在 4.5 之前的版本中根本没有讨论它。
  • @HansPassant 所以你是说如果我只使用我的第一个代码块并且根本不弄乱 serviceStatus - 它通常没问题吗?另外,您所说的 30 秒是什么意思...这是默认值还是您建议我使用 30000 而不是 100000?
  • 别惹它。 30 秒是 Windows 使用的默认超时时间。
  • 谢谢!请添加为答案
  • 我还强烈建议查看 Topshelf 项目,该项目使整个 Windows 服务的故事变得更容易topshelf-project.com。 Quartz.NET 在 Quartz.Server 项目中也包含了一个这样的示例。

标签: c# windows-services quartz.net


【解决方案1】:

正如@HansPassant 所说

ServiceBase 类已经处理服务状态的方式 在 99.9% 的情况下都足够好。 你应该不需要它,30 秒(默认)足以获得 99.9% 的所有服务 开始/停止。

但如果您需要处理长时间运行的收盘,documentation 表示担心

dwWaitHint

挂起的启动、停止所需的估计时间, 暂停或继续操作,以毫秒为单位。在指定之前 时间已经过去,服务应该下一次调用 具有递增 dwCheckPoint 的 SetServiceStatus 函数 值或 dwCurrentState 的变化。如果指定的时间量 通过 dwWaitHint 传递,并且 dwCheckPoint 没有增加或 dwCurrentState 没有改变,服务控制管理器或服务 控制程序可以假设发生了错误并且服务 应该停止。但是,如果该服务与其他服务共享一个进程 services,服务控制管理器不能终止服务 应用程序,因为它必须终止其他服务 分享过程。

和

dwCheckPoint

服务定期增加的检查点值 在漫长的开始、停止、暂停或 继续操作。例如,服务应该增加这个 值,因为它在完成初始化的每个步骤时 启动。调用操作的用户界面程序 服务使用此值来跟踪服务的进度 在长时间的操作中。此值无效,应为零 当服务没有启动、停止、暂停或继续时 操作挂起。

这澄清了walk-through 中的脚注。

服务控制管理器使用 dwWaitHint 和 dwCheckpoint SERVICE_STATUS 结构的成员来确定需要多少时间 等待 Windows 服务启动或关闭。如果您的 OnStart 和 OnStop 方法运行时间长,您的服务可以通过调用请求更多时间 使用递增的 dwCheckPoint 值再次设置服务状态。

基于此,我编写了这样的停止代码。请注意,我运行了一些非常长的任务并终止它们确实不是一个好主意,因此等待时间很长。

//set the status to pending close
var serviceStatus = new ServiceStatus
{
    dwCurrentState = ServiceState.SERVICE_STOP_PENDING,
    dwWaitHint = 120000//two minutes wait time
};
SetServiceStatus(this.ServiceHandle, ref serviceStatus);

Engine.Cancel();

while (Engine.IsRunning())
{
    System.Threading.Thread.Sleep(1000);
    serviceStatus.dwCheckPoint++;//updating the checkpoint so I don't get terminated
    SetServiceStatus(this.ServiceHandle, ref serviceStatus);
}

【讨论】:

  • 谢谢,如果您在此答案的顶部添加一个部分,指定 Hans Passant 在 cmets 中所说的内容,即在 99.9% 的情况下您应该保留默认值,我会很高兴接受这个。
  • 已添加。谢谢。它实际上使它变得更好。
猜你喜欢
  • 2012-03-15
  • 1970-01-01
  • 2016-09-26
  • 1970-01-01
  • 2019-08-14
  • 2020-03-03
  • 1970-01-01
  • 1970-01-01
  • 2021-06-28
相关资源
最近更新 更多