Azure DevOps托管代理并行运行Chromedriver时抛出进程占用异常
问题核心异常
Error: Exception has been thrown by the target of an invocation. -> The process cannot access the file 'D:\a_temp\TestResults\Chrome\102.0.5005.61\X64\chromedriver.exe' because it is being used by another process.
该异常仅在Azure DevOps流水线并行执行SpecRun.SpecFlow测试时触发,本地多线程运行无复现,本质是跨测试进程共享固定路径的chromedriver.exe文件,触发文件读写/运行锁争抢:本地多线程测试默认运行在单个测试进程内,chromedriver的下载、启动、销毁由同一个进程托管,且本地驱动缓存一般提前下载完成,不会触发运行时写文件逻辑;Azure DevOps流水线的并行测试如果是多进程级并行,所有进程默认访问agent上同一个共享临时目录下的驱动文件,多个进程同时触发驱动下载校验、启动逻辑时就会抛出占用异常。
排查思路
- 检查SpecRun配置:打开项目下的
.srprofile文件,查看<Execution>节点的testIsolation和parallelScope配置,确认是否开启了进程级隔离(testIsolation="Process"),该模式下每个测试线程会启动独立的测试进程,每个进程都会独立初始化WebDriver逻辑。 - 检查Azure DevOps测试任务配置:查看Visual Studio Test(或dotnet test)任务是否开启了测试切片并行分发,若开启多切片并行,每个切片是独立运行的测试进程,共享agent机器的全局临时目录。
- 检查WebDriver初始化逻辑:确认项目使用的chromedriver管理方式(Selenium.WebDriver.ChromeDriver NuGet包/WebDriverManager.Net等自动下载组件),是否未自定义驱动缓存路径,默认使用了全局共享的临时目录,且初始化时存在重复校验、覆盖下载驱动的逻辑。
- 检查agent进程残留:确认流水线运行前是否存在上一次任务未正常退出的chromedriver.exe进程,提前占住了对应路径的文件句柄。
修复方案
- 为每个并行测试实例分配独立的chromedriver缓存目录
若使用自动驱动管理组件,初始化驱动时不要使用默认共享路径,为每个执行实例生成唯一的临时目录存放驱动,从根源避免跨进程文件争抢:
若使用Selenium.WebDriver.ChromeDriver NuGet包,修改项目构建配置,禁止将chromedriver.exe输出到全局统一的TestResults目录,改为输出到每个测试进程独立的生成目录。// 为当前测试实例生成唯一驱动目录 var driverCachePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); Directory.CreateDirectory(driverCachePath); // 初始化驱动时指定独立目录(以WebDriverManager.Net为例) new DriverManager().SetUpDriver(new ChromeConfig(), version: "102.0.5005.61", architecture: Architecture.X64, driverCachePath); var chromeDriver = new ChromeDriver(driverCachePath); - 调整SpecRun并行隔离级别
无特殊进程隔离需求的场景下,修改.srprofile配置为线程级并行,减少跨进程锁冲突:
若必须使用进程级隔离,必须搭配上述独立驱动目录方案使用<Execution parallelScope="Feature" testThreadCount="根据agent配置设置合理并行数" testIsolation="Thread" /> - 流水线侧提前部署驱动、清理残留进程
- 在测试任务执行前增加PowerShell步骤,强制清理残留的chromedriver进程:
Get-Process chromedriver -ErrorAction SilentlyContinue | Stop-Process -Force - 提前下载对应版本的chromedriver到流水线独有的非共享路径(可使用
$(Agent.TempDirectory)\$(Build.BuildId)这类每次运行唯一的内置变量拼接路径),测试运行时直接指向该预下载路径,同时加环境变量判断禁用测试运行时的驱动自动下载、版本校验逻辑,避免运行时多个进程同时读写驱动文件。
- 在测试任务执行前增加PowerShell步骤,强制清理残留的chromedriver进程:
- 配置测试任务的切片隔离
若使用Azure DevOps多切片并行,配置每个测试切片使用独立的临时目录,在测试任务的环境变量中为每个切片设置独立的TEMP、TMP路径,基于切片ID生成唯一值,避免所有切片共享同一个临时目录。
内容的提问来源于stack exchange,提问作者benm912
相关产品推荐
相关产品推荐

