【问题标题】:.NET windows service aborted during system shutdown.NET Windows 服务在系统关闭期间中止
【发布时间】:2010-02-15 13:03:55
【问题描述】:

我的 Windows 服务是具有大量缓存的数据服务器。在服务 OnStop 期间,我保存了缓存,这样就不会丢失任何数据。保存缓存可能需要几分钟,所以为了防止 Windows 服务管理器超时,我使用 SetServiceStatus Win32 回调:

this.serviceStatus.currentState = (int)State.SERVICE_STOP_PENDING;
this.serviceStatus.checkPoint = 1;
this.serviceStatus.waitHint = 60000;
SetServiceStatus(Process.GetCurrentProcess().Handle, ref this.serviceStatus);

效果很好。

我还将 CanShutdown 设置为 true 并添加了 OnShutdown 以便该服务可以防止系统关闭。在这里,我实际上做了与 OnStop 相同的事情:

protected override void OnShutdown()
{
    this.OnStop(); 
    base.OnShutdown();
}

这不太好。当系统关闭时,当缓存被保存时,我得到“设备未准备好”。这表明 Windows 在停止/关闭之前中止服务。用 SetServiceStatus 来防止这种情况显然是行不通的。

如何获得更多时间(延迟重启)来完成保存?

欢迎提出任何建议。

【问题讨论】:

  • 快速提问 - waitHint 是 60 秒 - 1 分钟。那是你真正需要的吗? (你说需要几分钟)。
  • 我只需要成为举手并提出问题的人,即为什么要实现以这种方式运行的长寿命缓存。我不是说你的整个设计是无效的,我只是说我闻到了一些东西。它可能是来自法国的非常好的奶酪,也可能是非常糟糕的东西。
  • 我可以看到你举手了,戴夫。我知道你在想什么——让服务不要在内存中保留这么多的数据。但这就是缓存的想法。无论如何,缓存在几种情况下都会保存,但可以在系统关闭之前加载数据。并且服务器应该很少重新启动。但我需要为最坏的情况做好准备。
  • @dave +1 @maciej 如果您的数据在某种程度上很重要,您应该立即保存它,有些可能的边缘情况您无法涵盖,例如停电有人拔掉插头,没有更多的代码被执行,无论如何你的数据都消失了。

标签: c# .net windows-services timeout system-shutdown


【解决方案1】:

可以在this article on the BCL Team's blog 中找到处理此问题的首选方法。本文包含一些有关托管服务如何与 SCM 交互的背景知识,这对于理解为什么不再推荐问题中显示的方法非常重要。

简单地说,ServiceBase 现在为您处理服务状态管理,您的代码只需要在需要时请求额外的时间。阅读这篇文章,了解在 .NET 中编写 SCM 友好型服务的其他一些良好指南。

【讨论】:

  • 有用但不准确的答案。我不是在寻找从服务控制器请求更多时间的首选方式(但从现在开始会这样做)。在该博客的最后,我找到了有关为什么关闭与停止事件不同的信息。
【解决方案2】:

使用ManualResetEvent 可能是诀窍。

【讨论】:

  • 我看不到 ManualResetEvent 在这里会有什么好处。我无法控制请求服务关闭的线程,并且无论如何我都不想与之同步。我只希望它在 OnShutdown 结束之前阻止 Windows 终止我的服务。像 SetServiceStatus 这样的东西对 OnStop 起作用。
  • 由于 ManualResetEvent 基本上为您提供了一种让线程等待的方法,我认为它会有所帮助。不过,我可以理解您的观点-如果您无法检测到另一个进程何时会关闭您的服务。不过,就像@marc.d 建议的那样,考虑更频繁地保存这个缓存?他有一个非常有效的观点。
  • 这是一个极端的系统。我更频繁地保存缓存,但数据可能太多。它是一个写缓存。数据可以比我即时保存的速度快得多,而且它是一个恒定的流。诀窍是缓存重新排列数据(从水平到垂直),因此保存它的效率要高得多,因此我需要先积累一些数据才能保存它。因此,当系统关闭时,我可能根本没有数据或有很多数据。
  • 使用 ManualResetEvent 会比使用 Thread.Sleep 更高效
【解决方案3】:

经过一些测试,看来这是系统问题,而不是我的服务问题。

【讨论】:

    【解决方案4】:

    另一种简单的方法,经过数小时搜索如何包含setservicestatus 方法:

        protected override void OnStop()
        {
            stopTimer();
            m_run = false;
            while (m_queue.Count > 0)
                Thread.Sleep(500);
        }
    

    【讨论】:

    • 正如我在问题中提到的,这将在停止期间起作用,但在关机期间不起作用,因为当服务在指定时间内未从 OnStop 返回时(由系统中止)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多