【问题标题】:TopShelf service stuck in 'Stopping' state on exceptionTopShelf 服务因异常而陷入“停止”状态
【发布时间】:2014-09-16 21:23:26
【问题描述】:

我有一个 TopShelf (3.1.3) 服务,它在引发异常时处于“停止”状态。因此,不会调用任何服务恢复步骤,并且只有在通过“taskkill”手动终止服务时才能成功卸载服务。

在 TopShelf 中处理异常的推荐方法是什么?我不想简单地吞下/记录异常并继续。理想情况下,对 hostControl.Stop 的调用确实会将服务置于“停止”状态,但事实并非如此。

这个帖子问了一个类似的问题,但它没有提供答案: How to catch exception and stop Topshelf service?

想法?

HostFactory.Run(o =>
{
    o.UseNLog();
    o.Service<TaskRunner>();
    o.RunAsLocalSystem();
    o.SetServiceName("MyService");
    o.SetDisplayName("MyService");
    o.SetDescription("MyService");
    o.EnableServiceRecovery(r => r.RunProgram(1, "notepad.exe"));
});

public class TaskRunner : ServiceControl
{
    private CancellationTokenSource cancellationTokenSource;
    private Task mainTask;

    public bool Start(HostControl hostControl)
    {
        var cancellationToken = cancellationTokenSource.Token;
        this.mainTask = Task.Factory.StartNew(() =>
            {
                try
                {
                    while (!this.cancellationTokenSource.IsCancellationRequested)
                    {
                        // ... service logic ...
                        throw new Exception("oops!");
                    }
                }
                catch (Exception)
                {
                    hostControl.Stop();
                }
            });
        return true;
    }

    public bool Stop(HostControl control)
    {
        this.cancellationTokenSource.Cancel();
        this.mainTask.Wait();
        return true;
    }
}

【问题讨论】:

  • 服务没有成功停止,因为您在 Stop 方法中等待任务。删除该行并正确退出。

标签: c# error-handling windows-services topshelf


【解决方案1】:

看起来 topshelf 捕获异常并尝试很好地关闭,这意味着您可以通过关闭获得循环逻辑。例如,您有一个抛出异常的线程,topshelf 捕获它并要求所有可停止对象停止。其中之一是启动有问题线程的服务,因此它调用 thread.join();这意味着它正在等待自己完成,以便它可以完成。我认为这就是您的 task.wait() 发生的情况。

因此,解决方案实际上归结为:

  • 等待/加入超时
  • 在异常上架之前自行处理异常
  • 不要使用顶架

我最终遇到了超时,这会及时结束服务并允许我的异常日志记录运行。

【讨论】:

    【解决方案2】:

    尝试将while循环移到try catch块之外

    public bool Start(HostControl hostControl)
    {
        var cancellationToken = cancellationTokenSource.Token;
        this.mainTask = Task.Factory.StartNew(() =>
            {
                while (!this.cancellationTokenSource.IsCancellationRequested)
                {                
                    try
                    {
                        // ... service logic ...
                        throw new Exception("oops!");
                    }
                    catch (Exception)
                    {
                        hostControl.Stop();
                    }
                }
            });
        return true;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多