微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

任务应如何正确指示Windows服务关闭?

如何解决任务应如何正确指示Windows服务关闭?

我正在研究Windows服务的错误。该服务使用一个字段来跟踪对单个任务的引用。 OnStart,任务执行单个方法。该方法内部有一个循环,并以可配置的间隔调用数据库以监视另一个系统正在执行的工作。

protected override void OnStart(string[] args)
{
    _processorTask = Task.Run(() => StartProcessor());
}

我们偶尔会遇到一个问题,即Task死掉并记录异常情况很好,但是现有的管道并没有告诉服务停止,因此我们的服务监视器不知道有什么问题。

起初,我尝试添加只是添加对Stop()的调用

private void StartProcessor()
{
    var processor = new PEMonitoringProcessor(_tokenSource.Token);
    
    try
    {
        // The process loop is in the function. If this method exits,good or bad,the service should stop.
        processor.ProcessRun();
    }
    catch (Exception ex)
    {
        // An exception caught here is most likely fatal. Log the ex and start the service shutdown.
        if (log.IsFatalEnabled) { log.Fatal("A Fatal error has occurred.",ex); };
    }
    finally
    {
        Stop();
    }
}

但是,我的一位开发人员注意到OnStop方法中使用了一个令牌来指示Task停止然后等待。如果Task调用Stop并等待Stop返回并且OnStop正在等待Task结束,则对于此代码而言,这不是好兆头。

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

    try
    {
        _processorTask.Wait();
    }
    // logging & clean-up... 
}

我考虑了一个单独的任务,它不会被OnStop等待,它会检查第一个任务的状态,并在第一个任务完成,出现故障等情况下调用Stop,但这似乎有点不可思议。我还考虑过举办活动并尝试类似BeginInvoke的事情。

故意停止服务可以正常工作,因为OnStop通过Token发出信号,表明正在关闭。我试图解决Task方法返回或意外抛出并且我希望服务停止而不是变成僵尸的可能性。

解决方法

我看到的最直接的方式是这样的:

protected override void OnStart(string[] args) {
    _processorTask = Task.Run(() => StartProcessor());
    _processorTask.ContinueWith(x => {
        // x.Exception contains exception if any,maybe log it here
        Stop();
    },TaskContinuationOptions.NotOnCanceled);
}

protected override void OnStop() {
    //or !_processorTask.IsCompleted && !_processorTask.IsCanceled && !_processorTask.IsFaulted
    if (_processorTask.Status == TaskStatus.Running) {
        // only cancel and wait if still running. Won't be the case if service is stopping from ContinueWith above
        _tokenSource.Cancel();
        _processorTask.Wait(); 
    }
}

执行此操作的替代方法:

protected override async void OnStart(string[] args) {
    _processorTask = Task.Run(() => StartProcessor());
    bool cancelled = false;
    try {
        await _processorTask;
    }
    catch (OperationCanceledException) {
        // cancelled
        cancelled = true;
    }
    catch (Exception ex) {
        // log it?
    }

    if (!cancelled)
        Stop();
}

// OnStop stays the same

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。