You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows服务重启异常:跨设备表现不一致及Error 109故障

问题描述

我有一个ReactJS应用,调用C#编写的后端API,这个API负责检查并重启处于停止状态的Windows服务。但该功能在不同设备上表现不一致:部分设备能正常启停服务,部分设备必须重启笔记本才能启动服务。手动停止服务时,会弹出错误提示:

Windows无法停止本地计算机上的XXX服务。
错误109:管道已结束。

服务虽然最终会停止,但无法通过API自动重启。

前端调用API的函数

checkWebService = () => {
    fetch(getAPIURL() + '/common/CheckWebService', {
        method: 'POST', 
        headers: {
            'Content-Type': 'application/json; charset=utf-8'
        }
    }).then((response) => {
        if (!response.ok) { throw response }
        return response //we only get here if there is no error
    }).then(data => {
        console.log('restart web service data: ', data);
        this.setState({
            wsIsConnect: true,
        }, () => {
            this.doneLoading(false);
        });

    }).catch(err => {
        console.log('restart web service err: ', err);
        this.setState({
            wsIsConnect: false,
        }, () => {
            this.doneLoading(true);
        });
    });
}

C#后端API代码

using System.ServiceProcess;

//Activate the Windows Services if status it is stopped or pending
[SupportedOSPlatform("windows")]    //ServiceController only allows in Windows
[HttpPost("CheckWebService")]
public string CheckWebService()
{
    try
    {
        ServiceController service = new ServiceController(ServiceName);

        Debug.WriteLine("checkwebservice status" + service.Status);

        if ((service.Status.Equals(ServiceControllerStatus.Stopped)) || (service.Status.Equals(ServiceControllerStatus.StopPending)))
            service.Start();

        return "success";
    }
    catch (Exception ex)
    {
        Log("Error", ex.ToString(), "CheckWebService");

        return ex.ToString();
    }
}

问题分析与解决方案

核心问题拆解

  1. 错误109的本质:该错误说明服务停止时未正常关闭IPC管道,导致系统判定资源仍被占用,后续启动请求会因资源锁定失败。
  2. 后端逻辑短板:当前代码仅检查Stopped和StopPending状态,未处理服务停止后的资源残留情况;且未等待状态稳定就执行启动,容易触发失败。

针对性修复方案

1. 优化后端服务状态处理逻辑

修改C#代码,增加状态等待、重试机制,确保服务状态稳定后再执行操作:

using System.ServiceProcess;
using System.Threading;

[SupportedOSPlatform("windows")]
[HttpPost("CheckWebService")]
public string CheckWebService()
{
    try
    {
        using (ServiceController service = new ServiceController(ServiceName))
        {
            Debug.WriteLine($"当前服务状态: {service.Status}");

            // 等待停止中的服务完全终止
            if (service.Status == ServiceControllerStatus.StopPending)
            {
                service.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(30));
            }

            // 带重试的启动逻辑
            if (service.Status == ServiceControllerStatus.Stopped)
            {
                int retryCount = 3;
                bool startSuccess = false;
                while (retryCount > 0 && !startSuccess)
                {
                    try
                    {
                        service.Start();
                        service.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(30));
                        startSuccess = true;
                    }
                    catch (Exception startEx)
                    {
                        Debug.WriteLine($"启动失败,剩余重试次数: {retryCount-1},错误: {startEx.Message}");
                        retryCount--;
                        Thread.Sleep(2000);
                        service.Refresh(); // 刷新服务状态
                    }
                }

                if (!startSuccess)
                {
                    throw new Exception("多次重试后仍无法启动服务");
                }
            }

            return "success";
        }
    }
    catch (Exception ex)
    {
        Log("Error", ex.ToString(), "CheckWebService");
        return ex.ToString();
    }
}

2. 处理服务停止后的资源残留

  • 检查XXX服务的代码,确保停止时释放所有IPC管道、文件句柄等资源,从根源避免"管道已结束"错误。
  • 若无法修改服务代码,可在API中增加强制终止进程的逻辑(需谨慎使用,可能丢失未保存数据):
// 强制终止服务关联进程
private void ForceKillServiceProcess(string serviceName)
{
    var processQuery = $"SELECT * FROM Win32_Service WHERE Name = '{serviceName}'";
    using (var searcher = new ManagementObjectSearcher(processQuery))
    {
        foreach (var serviceObj in searcher.Get())
        {
            string processId = serviceObj["ProcessId"].ToString();
            if (!string.IsNullOrEmpty(processId) && processId != "0")
            {
                try
                {
                    Process process = Process.GetProcessById(int.Parse(processId));
                    process.Kill();
                    process.WaitForExit(10000);
                }
                catch (Exception ex)
                {
                    Debug.WriteLine($"强制终止进程失败: {ex.Message}");
                }
            }
        }
    }
}

可在启动重试失败后调用该方法,再尝试启动服务。

3. 权限与环境差异排查

  • 确保后端API运行账号拥有管理Windows服务的权限(如LocalSystem或管理员权限),部分设备可能因权限不足导致启动失败。
  • 检查不同设备的UAC设置,级别过高可能限制服务操作,需确保API进程以管理员身份运行。

4. 前端错误处理优化

当前前端仅通过HTTP响应状态判断结果,无法反映服务实际状态。可修改API返回服务最终状态,前端据此更新UI:

// 前端修改后的响应处理逻辑
.then(response => response.json())
.then(data => {
    console.log('restart web service data: ', data);
    this.setState({
        wsIsConnect: data.serviceStatus === 'Running',
    }, () => {
        this.doneLoading(false);
    });
})

后端对应返回结构:

return Json(new { 
    result = "success",
    serviceStatus = service.Status.ToString()
});

内容的提问来源于stack exchange,提问作者CnV

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 18:57:50