托管在 Windows 服务中的 WCF 服务在停止时挂起

Posted

技术标签:

【中文标题】托管在 Windows 服务中的 WCF 服务在停止时挂起【英文标题】:WCF Service hosted in Windows Service hangs on stop 【发布时间】:2019-01-06 10:07:21 【问题描述】:

我有一个托管在 Windows 服务 as described here 中的 WCF 服务。 我已经安排了服务的每晚重启,但有时重启失败并且服务保持/挂起在停止状态并且必须手动终止 EXE 进程。它看起来很可能挂在_ESSServiceHost.Close(); 行上,因为在该行之后没有任何内容记录在日志文件中。服务在繁忙时有可能但不太可能收到停止请求。 而且底层进程不能被杀死,因为它依赖于services.exe,所以只有服务器重启才能工作。

这种方法可能有什么问题?

  protected override void OnStop()
    
        try
        
            if (_ESSServiceHost != null)
            
                _ESSServiceHost.Close();
                _ESSServiceHost = null;
                //Never reaches the following line
                Tools.LogInfo("Services stopped.");
            
        
        catch (Exception ex)
        
            Tools.LogError(ex.Message);
        

这就是我停止服务的方式:

    private bool StopService(ServiceController scESiftServer)
    
        int i = 0;
        if (scESiftServer.Status == ServiceControllerStatus.Running)
        
            try
            
                scESiftServer.Stop();
            
            catch (Exception ex)
            
                Tools.LogEvent("Exception ...");
                return false;
            
            while (scESiftServer.Status != ServiceControllerStatus.Stopped && i < 120)
            
                Thread.Sleep(1000);
                scESiftServer.Refresh();
                i++;
            
        
        if (scESiftServer.Status != ServiceControllerStatus.Stopped)
        
            //This line gets executed
            Tools.LogEvent("Failed within 120 sec...");
            return false;
        
        else
        
            Tools.LogEvent("OK ...");
        
        return true;
    

这样的东西有帮助吗?

var task = Task.Run(() => _ESSServiceHost.Close(TimeSpan.FromSeconds(299)));
if (!task.Wait(TimeSpan.FromSeconds(300)))

    _ESSServiceHost.Abort();

但如果需要,应该通过 Close 方法在内部调用 _ESSServiceHost.Abort()。 目标框架是 4.5,安装的是 .NET 4.7.2。

发现服务可能在一系列格式错误的请求后挂起。 Expected record type 'Version', found '71'.

【问题讨论】:

尝试使用Close(TimeSpan timeout)(超时时间小于120s)方法而不是Close()。如果这有帮助,那么您在 WCF 服务中有长时间运行的任务(Close() 等待结束)。这意味着您需要增加 120 秒的 WindowsService 停止超时或处理长时间运行的 WCF 任务。 @Reniuz 我认为scESiftServer.Stop(); 异步运行只是向Windows 服务系统发送消息。您认为在我的StopService 方法中延长间隔或等待服务停止可以解决服务保持在“停止”状态的问题吗? 增加间隔或关闭 WCF 超时,甚至调用 Abort() 只是为了测试目的。我建议查看 WCF 服务,为什么它没有关闭,你有哪些长时间运行的任务? 我在日志中没有看到任何未完成的长时间运行的任务,但它们在服务器上出现了一些网络问题。处于停止状态的服务仍然能够执行未连接到 WCF 服务的任务(定时器任务)。我可以在es_tracelog.svclog 中看到很多异常。 @Reniuz 我已经添加了建议的超时,但是即使指定了超时,Close 方法仍然会挂起。挂起的时候没有对服务的请求,只是重启了服务。 【参考方案1】:

我在svclog 文件中发现,我的服务在周六和周日大约发生的一系列格式错误的请求后挂起。早上 5 点 15 分。错误消息为Expected record type 'Version', found '71'.Error while reading message framing format at position 0 of stream (state: ReadingVersionRecord)。但是我找不到这些格式错误的请求序列的原因,所以我试图修复服务以抵御“攻击”。

我修改了OnStop方法如下:

protected override void OnStop()

    try
    
        if (_ESSServiceHost != null)
        
            Tools.LogInfo("Stopping ESService.");
            var abortTask = Task.Run(() => _ESSServiceHost.Abort());
            var closeTask = Task.Run(() => _ESSServiceHost.Close(TimeSpan.FromSeconds(300)));
            try
            
                if (_ESSServiceHost.State == CommunicationState.Faulted)
                
                    Tools.LogInfo("ESSServiceHost.State == CommunicationState.Faulted");
                    if (!abortTask.Wait(TimeSpan.FromSeconds(60)))
                        Tools.LogInfo("Failed to Abort.");
                
                else
                
                    if (!closeTask.Wait(TimeSpan.FromSeconds(301)))
                    
                        Tools.LogInfo("Failed to Close - trying Abort.");
                        if (!abortTask.Wait(TimeSpan.FromSeconds(60)))
                            Tools.LogInfo("Failed to Abort.");

                                                
                
            
            catch (Exception ex)
            
                Tools.LogException(ex, "ESSServiceHost.Close");
                try
                
                    Tools.LogInfo("Abort.");
                    if (!abortTask.Wait(TimeSpan.FromSeconds(60)))
                        Tools.LogInfo("Failed to Abort.");
                
                catch (Exception ex2)
                
                    Tools.LogException(ex2, "ESSServiceHost.Abort");

                
            
            _ESSServiceHost = null;
            Tools.LogInfo("ESService stopped.");
        
    
    catch (Exception ex)
    
        Tools.LogException(ex,"OnStop");
    

今天星期一,我检查了 svclog,请求格式错误的“攻击”仍然存在,但我的服务过得很愉快。所以它似乎是固定的。此外,仅:

停止 ESService。

ESService 已停止。

事件已记录在我的日志文件中。没有中止等。所以我想将Close 调用放在单独的线程上解决了问题,但绝对不知道为什么。

【讨论】:

以上是关于托管在 Windows 服务中的 WCF 服务在停止时挂起的主要内容,如果未能解决你的问题,请参考以下文章

托管在 Windows 服务中的 WCF 服务在停止时挂起

如何在虚拟机中使用托管在 Windows 服务中的 WCF

Azure 功能无法访问托管在内部 windows 服务器中的 WCF 服务

托管在 Windows 服务中的 WCF 服务 - 应该由哪一个来完成所有工作?

域服务器和域外客户端中的 net.tcp wcf 服务(托管 Windows 服务)

Windows 服务(托管 WCF 服务)在启动时立即停止