【问题标题】:Terminating Windows Service in case of exception in processing thread在处理线程出现异常时终止 Windows 服务
【发布时间】:2016-09-21 04:40:45
【问题描述】:

我正在开发一个 Windows 服务应用程序,它使用 TPL 来启动它的主要处理任务。

处理任务是一个连续的 while 循环,一旦启动,它就会继续执行,直到发出来自 Windows 服务基础架构的取消请求。

启动实现如下:

    protected override void OnStart(string[] args)
    {
       continuousProcessingTask = Task.Factory.StartNew(
            () => DoStuffInAWhileLoopUntilCancelled(cancellation), cancellation, 
                     TaskCreationOptions.LongRunning, TaskScheduler.Default);
    }

问题是,如果主任务中的某处(在 DoStuffInAWhileLoopUntilCancelled 方法中)发生未经处理的异常,我希望终止服务。

更准确地说,我希望在处理任务中发生未处理的异常时服务处于一致状态。使用上面的 sn -p 最终会出现正在运行的 windows 服务但处理任务终止的情况,在我看来这是不一致的。 在我的理解中,一致的行为意味着处理任务/线程和父服务进程都在运行,或者什么都没有运行。

我最终采用了延续方法,如果主处理线程失败则关闭服务进程:

    protected override void OnStart(string[] args)
    {
    continuousProcessingTask = Task.Factory.StartNew(
        () => DoStuffInAWhileLoopUntilCancelled(cancellation), cancellation, 
                 TaskCreationOptions.LongRunning, TaskScheduler.Default)
    .ContinueWith(OnTaskCompleted);
    }

    void OnTaskCompleted(Task task)
    {
        if (task.IsFaulted)
        {
            if (task.Exception != null)
            {
                Service.EventLog.SafeWriteEntry(task.Exception.ToString(), EventLogEntryType.Error);
            }
            // shut down the application
            System.Environment.Exit(-1);
        }
    }

但我不确定这是否是这里推荐的方法 - System.Environment.Exit 看起来很丑(并且打破了类隔离)。是否有其他选项可用于处理此模式中的主处理任务的终止(第一个代码 sn-p)?

UPD1: 澄清了上面的问题。

【问题讨论】:

  • 如果这种情况发生在服务本身,为什么不直接在服务上调用 Stop 呢? msdn.microsoft.com/en-us/library/…
  • 这个应用程序可以作为控制台进程(对于开发人员)和作为服务(对于产品)运行。这是个好主意,谢谢,我可以尝试在 System.Environment.Exit 上调用 Stop。但是现在我明白我的问题稍微宽泛了——我一般应该如何在主要处理任务中处理未经处理的异常......?
  • 当你在控制台应用程序中运行时——只要让它像往常一样退出主方法。除非绝对必要,否则不要使用 Environment.Exit(或 FailFast 等)。如果您遇到未处理的异常 - 您的应用程序应该记录、清理并正常退出。如果这是一项始终在运行的服务 - 将其配置为自动重启。
  • 谢谢。基本上,这就是我对这些服务所拥有的——它们根据服务恢复操作无限期地重新启动。看起来,我现在拥有的(第二个代码 sn-p)几乎就是它,除了优雅退出(只需要替换 System.Environment.Exit)。 raidensan 的论点是服务应该连续运行,所以我想知道是否应该在已经运行的服务进程中完成处理任务重启......(这可以被检测到并继续完成)
  • 一种选择是重新抛出异常,这将导致进程异常终止。这样做的潜在优势是它应该触发 Windows 服务故障处理,允许您将服务配置为在故障时自动重新启动。

标签: c# multithreading exception-handling windows-services task-parallel-library


【解决方案1】:

由于服务的预期行为连续运行,因此在出现异常时终止服务可能不是一个好主意。如果您的应用需要多次执行某个任务,控制台应用就足够了。

更好的方法是正确处理异常(取决于上下文)并保持服务运行。请注意:正在运行的服务并不一定意味着它正在执行某些任务。您可以保持服务运行并仅在需要时执行任务。

但是,如果您需要立即终止服务,您可以使用FailFast

【讨论】:

  • 应用程序必须执行连续的工作调度,直到停止请求未发送到服务。但是,如果在主调度任务中出现异常(例如 - 数据库在一段时间内无法访问),则任务终止,但服务进程继续运行(什么也不做,因为主处理任务已关闭)。更广泛的问题是 - 我应该终止服务,还是应该尝试重新启动调度任务,还是应该做其他事情? :-/ 至于 FailFast - 不确定我是否需要将报告发送给 Microsoft :)
  • 保持服务运行并尝试重新启动您的任务。此外,FailSafe 和 Environment.Exit 都会终止服务本身以及所有子进程。
猜你喜欢
  • 1970-01-01
  • 2012-09-02
  • 1970-01-01
  • 2011-07-31
  • 2017-08-13
  • 1970-01-01
  • 2014-09-24
  • 2018-10-27
  • 1970-01-01
相关资源
最近更新 更多