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

.NET7 Worker Service部署Windows服务遇Error1053及先决条件咨询

.NET 7 Worker Service 作为Windows服务启动报错Error 1053排查方案

问题描述

使用.NET 7开发Worker Service,本地通过dotnet build运行正常,但发布后作为Windows服务后台运行时,持续触发Error 1053(服务启动超时)。服务依赖Selenium WebDriver提取数据,服务器已安装最新版ChromeDriver与Chrome浏览器,问题仍未解决。疑问:

  1. 是否因服务器未识别驱动导致启动超时?
  2. 在Windows Server虚拟机上运行该服务,还需满足哪些先决条件?

使用的NuGet包

RUN dotnet add package Selenium.Support --version 4.8.1
RUN dotnet add package Azure.Storage.Blobs --version 12.15.1
RUN dotnet add package Microsoft.Azure.Functions.Extensions --version 1.1.0
RUN dotnet add package Microsoft.NET.Sdk.Functions --version 4.1.1
RUN dotnet add package Microsoft.VisualStudio.Azure.Containers.Tools.Targets --version 1.17.2
RUN dotnet add package System.Threading.AccessControl --version 7.0.1

其他安装项:

  • 最新稳定版ChromeDriver
  • Chrome浏览器

核心代码

using Azure.Storage.Blobs;
using Screenshot_WorkerService.Interface;
using Screenshot_WorkerService.Service;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.Extensions;
using System.Drawing;

namespace Screenshot_WorkerService
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;
        private readonly IBlobStorageServiceClient _blobServiceClient;

        public Worker(ILogger<Worker> logger, IBlobStorageServiceClient blobServiceClient)
        {
            _logger = logger;
            _blobServiceClient = blobServiceClient;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("Worker running at: {time}", DateTime.Now);
                var timeout = 10;

                _logger.LogInformation("Reading urls values from blob");
                var urlConfiguration = await _blobServiceClient.DownloadConfigrationBlob();

                if (urlConfiguration.Urls is not null)
                {
                    foreach (var item in urlConfiguration.Urls)
                    {
                        _logger.LogInformation("Preparing headless web browser");
                        var options = new ChromeOptions();
                        options.AddArguments(new List<string> { "--headless", "--hide-scrollbars" });

                        using var driver = new ChromeDriver(options);
                        _logger.LogInformation("web browser complete");
                        driver.Manage().Window.Size = new Size(item.Width, item.Height);
                        driver.Navigate().GoToUrl(item.Url);
                        driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(timeout);

                        try
                        {
                            _logger.LogInformation($"Searching class element: {timeout}");
                            var element = new WebDriverWait(driver, TimeSpan.FromSeconds(timeout)).Until((d) =>
                            {
                                d.Navigate().GoToUrl(item.Url);
                                Thread.Sleep(5000);
                                return d.FindElement(By.ClassName("v-menu"));
                            });

                            var screenshot = driver.TakeScreenshot();
#if DEBUG
                            screenshot.SaveAsFile($"{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.png");
#endif
                            //Save to blobStorage
                            _blobServiceClient.UploadImageToBlobAsync(screenshot);

                        }
                        catch (NoSuchElementException e)
                        {
                            // try Login
                            _logger.LogInformation($"Exception: {e.Message}");
                            _logger.LogInformation($"Trying automate login");

                            var username = driver.FindElement(By.Id("input-12\""));
                            username.Clear();
                            username.SendKeys("");

                            var password = driver.FindElement(By.Id("input-13"));
                            password.Clear();
                            password.SendKeys("");

                            var loginButton = driver.FindElement(By.XPath("//button[@class='v-btn v-btn--block v-btn--outlined theme--dark v-size--default primary--text']\r\n"));
                            loginButton.Click();

                            driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(timeout);

                            var screenshot = driver.TakeScreenshot();

#if DEBUG
                            screenshot.SaveAsFile($"{DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss")}.png");
#endif
                            //Save to blobStorage
                            _blobServiceClient.UploadImageToBlobAsync(screenshot);
                        }
                        catch (WebDriverTimeoutException e)
                        {
                            _logger.LogInformation($"Exception trying login was timed out: {e.Message}");
                        }
                        catch (Exception e) {
                            _logger.LogInformation($"Exception: {e.Message}");
                        }
                    }
                }
                else
                {
                    _logger.LogWarning("Reading returned no urls, check the blobstorage for url values");
                }
                _logger.LogWarning("Done!");
                await Task.Delay(TimeSpan.FromMinutes(20), stoppingToken);
            }
        }
    }
}

问题排查与解决方案

1. 驱动识别是否导致启动超时?

是,大概率是驱动相关问题引发的启动超时,核心原因包括:

  • Windows服务默认使用Local System账户,该账户的环境变量、权限与本地测试账户不同,可能无法找到Chrome或ChromeDriver的路径。
  • ChromeDriver未放入服务发布目录,或Local System账户无访问驱动文件的权限。
  • 无头模式参数不全,导致Chrome启动失败,阻塞服务初始化流程,超过30秒默认启动超时。

2. Windows Server运行的先决条件与修复步骤

(1)严格匹配Chrome与ChromeDriver版本

必须保证两者版本完全一致(小版本号也要对应),可通过chrome://version/查看Chrome版本,下载对应版本的ChromeDriver。

(2)调整服务运行账户与权限

  • 避免使用Local System账户,改用本地管理员账户运行服务,该账户拥有桌面交互权限(Selenium需要访问桌面会话)。
  • 若坚持使用Local System,需在服务属性中勾选「允许服务与桌面交互」(部分Windows Server版本可能受限)。
  • 确保运行账户拥有以下权限:
    • 访问Chrome安装目录(默认C:\Program Files\Google\Chrome\Application\)
    • 访问ChromeDriver所在目录
    • 访问Worker Service发布目录

(3)完善ChromeOptions配置

Windows服务环境下,仅--headless和--hide-scrollbars参数不足以启动Chrome,需补充以下关键参数:

var options = new ChromeOptions();
options.AddArguments(new List<string> { 
    "--headless=new", // 新版无头模式,兼容性更好
    "--hide-scrollbars",
    "--no-sandbox", // 禁用沙箱,服务环境必备
    "--disable-gpu", // Windows下禁用GPU加速
    "--disable-dev-shm-usage", // 解决容器/服务环境内存不足问题
    "--start-maximized" // 确保窗口尺寸正确
});
// 手动指定Chrome路径,避免服务账户找不到
options.BinaryLocation = @"C:\Program Files\Google\Chrome\Application\chrome.exe";

(4)显式指定ChromeDriver路径

将ChromeDriver.exe放入服务发布目录,或在代码中显式指定驱动路径,同时隐藏命令行窗口:

// 指定驱动所在目录
var driverService = ChromeDriverService.CreateDefaultService(AppContext.BaseDirectory);
// 隐藏ChromeDriver命令行窗口,服务环境更友好
driverService.HideCommandPromptWindow = true;
using var driver = new ChromeDriver(driverService, options);

(5)延长服务启动超时时间

Windows服务默认启动超时为30秒,Selenium初始化可能需要更长时间,可通过注册表调整:

  1. 打开注册表编辑器,定位到HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
  2. 新建或修改ServicesPipeTimeout(DWORD类型),设置值为60000(60秒)或更长
  3. 重启服务器使设置生效

(6)修复代码中的潜在问题

  • 移除Thread.Sleep:WebDriverWait的Until方法中使用Thread.Sleep(5000)会阻塞等待逻辑,应完全依赖WebDriverWait的超时机制。
  • 异步方法添加await:UploadImageToBlobAsync是异步方法,需添加await,否则会导致异步操作未完成就继续执行,引发资源泄漏或逻辑错误:
    await _blobServiceClient.UploadImageToBlobAsync(screenshot);
    
  • 修正元素定位错误:登录部分By.Id("input-12\"")包含多余引号,应改为By.Id("input-12"),否则会引发NoSuchElementException,延长服务启动时间。

(7)日志与事件排查

  • 配置文件日志(如Serilog),将详细日志输出到指定文件,便于排查服务启动时的错误。
  • 查看Windows事件查看器的「应用程序日志」和「系统日志」,里面会记录服务启动失败的具体错误信息。

内容的提问来源于stack exchange,提问作者Ahune ajé o ahe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 21:17:25