资讯动态

ASP.NET Core Helix 分布式测试实践:队列矩阵、本地运行与故障排查指南

发布时间:2026/9/6 23:13:55 来源:尧图企业网站定制
ASP.NET Core Helix 分布式测试实践队列矩阵、本地运行与故障排查指南【免费下载链接】aspnetcoreASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.项目地址: https://gitcode.com/GitHub_Trending/as/aspnetcoreHelix 是 .NET 团队使用的分布式测试平台ASP.NET Core 仓库用它将测试项目的 publish 产物打包成测试负载payload分发到 Windows、macOS、Linux 各队列的机器上并行执行并回传结果。本文基于 docs/Helix.md 并结合当前仓库中的构建脚本与 MSBuild 目标eng/helix/、eng/targets/Helix.*完整讲解如何本地提交 Helix 任务、当前队列矩阵的实际定义、CI 流水线中 Helix 的触发策略、结果查看路径以及隔离测试quarantine、HelixContent负载扩充、测试跳过等日常开发流程读完即可独立完成跨平台测试验证与 Helix 运行问题分析。一、Helix 在 ASP.NET Core 中的工作方式整体流程可以概括为三步源自 docs/Helix.md为每个要测试的测试项目构建一个 Helix 负载payload其内容包含该项目及相关引导脚本的 publish 目录携带该负载的作业job被发送到各操作系统组合对应的队列例如文档早期示例中的Windows.10.Amd64.ClientRS4.VS2017.Open、OSX.1100.Amd64.Open、Ubuntu.1804.Amd64.OpenHelix 平台负责解包、执行作业并汇报结果。需要注意队列名称中的语义以.Open结尾的是公共队列去掉.Open的是对应的内部队列src/Testing/src/xunit/SkipOnHelixAttribute.cs 中的注释明确说明了两者的对应关系。当前仓库中队列的单一事实来源是 eng/targets/Helix.Common.props。该文件中的注释说明它“在 Helix.proj 与 .csproj 之间共享”并按“PR 检查”与“完整矩阵”两种场景拆分PR 检查队列IsHelixPRChecktrue时对应 aspnetcore-ci 与 aspnetcore-quarantined-pr 两条流水线Ubuntu.2404.Amd64.Open、OSX.26.Arm64.Open、Windows.Amd64.VS2026.Openeng/targets/Helix.Common.props完整矩阵队列对应 aspnetcore-helix-matrix、aspnetcore-quarantined-tests 以及RunHelix.ps1属性队列当前仓库实际值平台HelixQueueAlmaLinuxAlmaLinux.10.Amd64.Open容器镜像 almalinux-10-helix-amd64LinuxHelixQueueAlpineAlpine.323.Amd64.Open容器LinuxHelixQueueAzureLinuxAzureLinux.30.Amd64.Open容器LinuxHelixQueueDebianDebian.13.Amd64.Open容器LinuxHelixQueueFedoraFedora.44.Amd64.Open容器LinuxHelixQueueArmDebianDebian.13.Arm64.OpenARM64 容器Linux—OSX.15.Amd64.OpenmacOS—Windows.Amd64.Server2022.OpenWindows—Windows.11.Amd64.Client.OpenWindows—Windows.Amd64.VS2026.OpenWindows—windows.11.arm64.open仅当IsWindowsOnlyTest ! true因为 IIS Express 不支持 arm64Windows其中 Linux 队列采用友好队列名宿主Docker 镜像的三段式写法容器镜像来自 dotnet-buildtools/prereqs 系列见 eng/targets/Helix.Common.props。可见相比文档初稿中“Windows10 / OSX / Ubuntu1804”的必需队列当前仓库已演进到更新的 OS 版本与容器化 Linux 队列——阅读旧资料时请以该文件为准。另外该文件还根据HelixTargetQueue派生出三个平台判断属性eng/targets/Helix.Common.propsIsArm64HelixQueue、IsWindowsHelixQueue、IsMacHelixQueue供后续 targets 中按平台注入预执行命令使用。二、本地运行单个测试项目的 Helix 任务对某一个测试项目运行 Helix 测试的命令docs/Helix.md 原文步骤.\eng\scripts\RunHelix.ps1 -Project path\mytestproject.csproj该脚本会先 restore然后 publish 所有相关测试项目同时包含在 Helix 机器上先安装正确 dotnet runtime/SDK、再运行测试程序集的引导脚本最后把作业上传到 Helix。结合 eng/scripts/RunHelix.ps1 的源码完整参数与行为如下参数说明-Project必填要 publish 并发送到 Helix 的测试项目-HelixQueues要使用的队列或;分隔脚本默认值Windows.10.Amd64.Server20H2.Open注释中列出 Debian、Ubuntu、OSX、Windows Server/Client 等受支持队列-RunQuarantinedTests开关默认不跑隔离测试设为$true时只跑隔离测试-TargetArchitecture构建架构x64/x86/arm64默认x64-MSBuildArguments剩余参数透传给 MSBuild 的附加参数脚本内部实际执行的是eng/scripts/RunHelix.ps1dotnet msbuild $Project /t:Helix /p:TargetArchitecture$TargetArchitecture /p:HelixTargetQueues$HelixQueues /p:RunQuarantinedTests$RunQuarantinedTests /p:_UseHelixOpenQueuestrue /p:CrossgenOutputfalse /p:ASPNETCORE_TEST_LOG_DIRartifacts/log /p:DoNotRequireSharedFxHelixtrue /p:NUGET_PACKAGES$NUGET_PACKAGES MSBuildArguments几个值得注意的细节队列串中的;会被转义为%3B再传给 MSBuildeng/scripts/RunHelix.ps1这是 MSBuild 多值分隔的常规处理_UseHelixOpenQueuestrue表示本地提交使用公共队列无需HelixApiAccessToken内部队列才需要访问令牌见 eng/helix/helix.proj脚本开头的黄色提示eng/scripts/RunHelix.ps1给出了共享框架相关的关键约束若测试需要共享框架请先执行./build -pack -all若产物都是最新的追加/p:NoBuildtrue若只是测试项目过期追加/p:BuildProjectReferencesfalse本地运行时HelixBuild取值为private-用户名而 CI 中取构建号eng/helix/helix.proj便于在 Helix 上区分来源。三、负载如何构建从 MSBuild 目标到测试程序集/t:Helix对应的目标定义在 eng/targets/Helix.targets它只是把当前项目路径作为ProjectToBuild转发给 eng/helix/helix.proj一个使用Microsoft.DotNet.Helix.Sdk的项目后者是真正的作业编排入口。关键的构建链路如下Gather目标eng/helix/helix.proj对(ProjectToBuild)逐项目调用CreateHelixPayload收集输出项(HelixWorkItem)CreateHelixPayload/_CreateHelixPayloadInnereng/targets/Helix.targets按 TFM 逐个构建每个测试项目产出工作项_CreateHelixWorkItemeng/targets/Helix.targets先执行一次Publish注意此处刻意移除HelixTargetQueue属性保证只 publish 一次而不是每个队列各 publish 一次若 publish 目录没有Directory.Build.props/Directory.Build.targets且TestDependsOnAspNetRuntime不为 true则复制 eng/helix/content/Directory.Build.empty.in 空文件进去目的是“把 Helix 测试与父目录里恰好存在的 MSBuild 内容隔离开”源码注释原话避免宿主机目录上的构建配置污染测试执行环境生成的HelixWorkItem携带TestAssembly测试 DLL、PayloadDirectory、PreCommands/PostCommands、队列名、RunQuarantined、超时等元数据并且 Windows/非 Windows 队列分别指定执行命令runtests.cmd/runtests.sh参数依次为targets.txt、运行时版本、队列名、架构、是否隔离测试、HelixTimeout、是否安装 Playwrighteng/targets/Helix.targets。eng/targets/Helix.props 定义了工作项层面的默认配置值得逐项了解DefaultHelixTimeout00:45:00即每个工作项默认 45 分钟超时耗时更长的项目如需要 scaffold、restore、build、运行真实应用的模板测试在自己的.csproj中覆盖HelixTimeoutHelixTestName $(MSBuildProjectName)--$(TargetFramework)这就是日志里形如Microsoft.AspNetCore.Identity.Test--net8.0的工作项名的来源NodeVersion固定为20.7.0三个“测试依赖”开关的默认值TestDependsOnAspNetPackagesfalse、TestDependsOnAspNetAppPackagesfalse、TestDependsOnAspNetRuntimetrueeng/targets/Helix.props。注释解释了取舍多数测试依赖.dotnet/目录布局但只有少数restore 或测包的才真正需要 NuGet 包默认把 eng/helix/content/ 整个目录$(RepoRoot)eng\helix\content\**\*排除*.in纳入HelixContent——这正是 runtests 脚本、JDK/Node 安装脚本等引导内容进入每个工作项负载的途径HelixContent的默认元数据是“不参与 Build 目录、总是进入 Publish 目录”eng/targets/Helix.props。eng/targets/Helix.targets 还展示了按“依赖”注入预执行命令HelixPreCommand的模式TestDependsOnJavatrueWindows 队列上通过RunPowershell.cmd InstallJdk.ps1 21.0.5安装 JDK 并设置JAVA_HOME其他非 Mac 平台走./installjdk.shTestDependsOnMssqltrue且 Windows 非 ARM64安装 SQL Server LocalDBTestDependsOnIIStrue且IsWindowsOnlyTesttrue把 IIS 的 schema 更新脚本与测试证书作为HelixContent打入负载并预执行update_schema.ps1、UpdateIISExpressCertificate.ps1TestDependsOnNodetrueWindows 走InstallNode.ps1其余平台走installnode.sh $(NodeVersion)TestDependsOnPlaywrighttrue跳过 AlmaLinux/Alpine/AzureLinux/Debian/Fedora 容器队列与 Ubuntu.2404 队列SkipHelixQueues、跳过 ARMSkipHelixArmWindows 上额外预执行installPlaywrightReqs.ps1。负载到达 Helix 机器后runtests.sh会执行eng/helix/content/runtests.shdotnet $HELIX_CORRELATION_PAYLOAD/HelixTestRunner/HelixTestRunner.dll \ --targets-file $targetsFile --runtime $2 --queue $3 --arch $4 \ --quarantined $5 --helixTimeout $6 --playwright $7也就是说真正在远端解释执行、逐工作项运行测试程序集的是HelixTestRunnersrc/Tools/HelixTestRunner。targets.txt是工作项批处理机制的产物BatchSmallWorkItems目标eng/helix/helix.proj通过RepoTasks.BatchHelixWorkItems任务把最多HelixWorkItemMaxBatchSize默认 20个小测试程序集合并进同一个工作项以降低“上传负载、获取机器、结果上报”的每工作项固定开销凡是需要 IIS/Playwright/Java/Node/MSSQL 依赖、或HelixTimeout偏离默认值的项目都会设置SkipHelixWorkItemBatchingtrue不参与批处理eng/targets/Helix.targets。批处理带来的另一个约束见 eng/helix/helix.proj 注释最大的批次总时长必须留在工作项超时之内。eng/helix/helix.proj 还定义了关联负载correlation payload即在测试负载之外随作业一起下发的内容刚构建的 App.Ref / App.Runtime 共享框架布局IncludeAspNetRuntime目标会检查 TargetingPack 布局是否存在缺失时直接报“some tests are guaranteed to fail”的错误本地可用DoNotRequireSharedFxHelixtrue放宽——这正是RunHelix.ps1传该参数的原因非 shipping 的 ASP.NET Core 共享框架传输包以Microsoft.Internal.Runtime.AspNetCore.Transport版本为哨兵HelixTestRunner的 publish 输出dotnet-dump、dotnet-ef、dotnet-serve三个工具的 nupkgRestoreDotnetTools目标先dotnet tool restore再定位包路径以AsArchivefalse原样下发测试配置文件 eng/test-configuration.json通过HelixTestConfigurationFilePath自动加入关联负载。四、CI 流水线中的 Helix 矩阵与合入规范docs/Helix.md 列出的四条流水线及职责当前仓库的队列映射见 eng/targets/Helix.Common.props 中的注释aspnetcore-ci在“必需队列”上运行非隔离测试是 PR 的必过检查也在所有分支的所有构建上运行aspnetcore-helix-matrix在 public main 上每天两次对全部队列运行非隔离测试aspnetcore-quarantined-pr只对必需队列运行隔离测试触发时机为 PR 以及 main 上每 4 小时一次aspnetcore-quarantined-tests只在 public main 上每天 23:00 对全部队列运行隔离测试。四条流水线都不是必须逐一点名也可以随时手动排队运行Run Pipeline选择分支/tag 与 commit。合入流程约定checkin process expectations常规 PR 流程由 aspnetcore-ci 保证必需队列为绿如果你的改动“很可能”超出必需队列范围影响跨平台行为应在合并前针对自己的分支手动触发一次 aspnetcore-helix-matrix。该流水线虽非必过门禁但如果它被你的改动弄坏你必须要么立即回滚、要么把相关测试隔离quarantine绝不允许让它停留在红色状态。隔离测试的名单由 eng/QuarantinedTests.AfterArcade.props 等文件维护RunQuarantinedTests属性在 eng/targets/Helix.Common.props 中默认置为false且按全局属性锁定不允许被随意覆盖。五、查看 Helix 运行结果文档给出的两条路径最简路径Azure Pipelines 的 Tests 选项卡。现在它应显示错误摘要并附带相关 console log 附件深入 Helix Web API从失败测试的 Debug 选项卡拿到HelixJobId与HelixWorkItemName请求工作项详情https://helix.dot.net/api/2019-06-17/jobs/jobId/workitems/workitemname返回中还有更多可继续下钻的 URL。文档给出的完整下钻链路是work items 链接去掉/workitems得到 jobs 链接打开 jobs 的DetailsUrl再打开JobsListJSON最后点击其中某个PayloadUrl即可下载该测试作业负载的 zip 包用于完整检查作业内容zip 内容结构与 publish 目录一致可参考 eng/helix/content 说明的“负载内容 测试二进制 引导脚本”。另一个实用技巧build.cmd的 Tests 日志中嵌有 Helix 作业链接。一次典型的多队列提交日志形如节选自 docs/Helix.md 的示例日志队列与作业 ID 已泛化Sending Job to Ubuntu.1804.Amd64.Open... Sent Helix Job; see work items at https://helix.dot.net/api/jobs/jobId-1/workitems?api-version2019-06-17 Sending Job to Windows.11.Amd64.ClientPre.Open... ... Waiting for completion of job jobId-1 on Ubuntu.1804.Amd64.Open Job jobId-1 on Ubuntu.1804.Amd64.Open is completed with 138 finished work items. Stopping Azure Pipelines Test Run Ubuntu.1804.Amd64.Open error : Work item Microsoft.AspNetCore.Identity.Test--net8.0 in job jobId-2 has failed. Failure log: https://helix.dot.net/api/2019-06-17/jobs/jobId-2/workitems/Microsoft.AspNetCore.Identity.Test--net8.0/console从中可以直接读出三个信息各队列的作业 ID、完成的 work item 数量以及失败工作项的 console 日志地址/console后缀。关于队列本身的可观测性Helix 主页只展示公共队列信息不涉及 BYOC 池与内部队列而所有队列 agent 的实时、完整信息可以查 Helix 的公开 API 端点https://helix.dot.net/api/2018-03-14/info/queues六、测试失败时如何本地复现docs/Helix.md 给出的本地模拟方式dotnet publish cd the publish directory dotnet vstest My.Tests.dll这与远端行为是一致的Helix 上跑的也是 publish 目录里的测试程序集只是通过runtests.sh/runtests.cmd HelixTestRunner 包装见第三节。与本地运行的关键差异大多数“本地能过、Helix 上不过”或相反的测试根源在于它们依赖源码可访问。Helix 负载只包含 publish 目录里的东西测试若依赖其他文件就必须显式打入负载。做法是使用HelixContent项ItemGroup HelixContent Include$(RepoRoot)src\KeepMe.js/ HelixContent Include$(RepoRoot)src\Project\**/ /ItemGroup默认这些文件会放进负载根目录要放到别的目录用Link单个文件的完整目标路径或LinkBase目录前缀ItemGroup HelixContent Include$(RepoRoot)src\KeepMe.js Link$(MSBuildThisFileDirectory)\myassets\KeepMe.js/ HelixContent Include$(RepoRoot)src\Project\** LinkBase$(MSBuildThisFileDirectory)\myassets/ /ItemGroup从源码看HelixContent之所以能进入负载是因为在$(BuildHelixPayload)为 true 时它们被转换为Contenteng/targets/Helix.targets随 Publish 一并下发同样的机制被Helix.targets自身用来打包 IIS 工具脚本与证书前文TestDependsOnIIS分支。七、在 Helix 上跳过测试docs/Helix.md 列出的两种主要方式整个测试项目退出 Helix在 csproj 中设置BuildHelixPayloadfalse/BuildHelixPayload该属性的默认值来自IsTestProject。从 eng/targets/Helix.targets 可以看到BuildHelixPayload的完整判定链目标队列与项目平台不匹配、SkipHelixArm、SkipHelixAlpine、SkipHelixQueues命中时都会将其置为false——即“平台不匹配”的项目在构建负载阶段就被自动跳过单个测试退出用[SkipOnHelix(url to github issue)]特性。实现见 src/Testing/src/xunit/SkipOnHelixAttribute.cs它是ITestConditionIsMet返回!(OnHelix() ShouldSkip())可选设置Queues属性按队列过滤支持通配All.OSX、All.Ubuntu、All.Linux也支持以分号分隔的具体队列名如Windows.Amd64.Server2022.Open;OSX.1015.Amd64.Open比较时兼容公共/内部队列的.Open后缀差异特性强制要求传入 issue URLArgumentThrowHelper.ThrowIfNullOrEmpty呼应文档的要求每个被跳过的测试都必须建 issue并把链接写在这两种跳过方式旁边的注释里。八、更新 Helix 矩阵的流程docs/Helix.md 中“Process for updating helix matrix”的核心目标是在成本/抖动与对受支持发行版的覆盖之间取得平衡每个产品版本启动时根据流行度、感知风险和该 OS 版本的剩余支持期选定一组要跑的队列/版本/架构每当有新 OS 上线时先请 CTI社区技术基础设施团队在其上试跑如果 Helix 已支持则提交 PR 把该队列加进 helix-matrix 以观察是否有失败——没有失败就不合并若合适的队列尚不存在可以向 dotnet-buildtools-prereqs-docker 仓库提 PR 添加容器镜像即使最终不保留本仓库的改动这个 PR 本身也有价值OS 支持日历与当前队列清单即 eng/targets/Helix.Common.props是决策依据。向 Helix 添加新 Docker 镜像的示例流程文档以 dotnet-buildtools-prereqs-docker#398 为范例更新该仓库的manifest.json加入新 dockerfile 条目同时把 dockerfile 文件加入该仓库新队列的 ID 最终会出现在 dotnet/versions 仓库中的image-info.dotnet-dotnet-buildtools-prereqs-docker-main.json里拿到队列 ID 后即可回填到本仓库的 eng/targets/Helix.Common.props。九、排查 Helix 运行时长问题Helix 的全部作业数据可在 KustoAzure Data Explorer 的engsrvprod集群、engineeringdata数据库中查询。给定一个 job id可用如下查询找出耗时最长的测试项目docs/Helix.md 原文查询WorkItems | where JobName bc108374-750c-4084-853e-bc5b9b0d553e | where Name ! JobName | extend RunTime Finished-Started | top 20 by RunTime desc | project FriendlyName, RunTime为什么要关心这个文档解释为了吃满 Helix 的最大扇出fan-out我们希望测试项目尽量小——因为耗时最长的测试项目就是整个 Helix 作业完成时间的瓶颈最慢的工作项决定整体闸门。这也解释了当前仓库中 20 个工作项上限的批处理设计eng/helix/helix.proj既摊薄固定开销又保证批次总时长落在 45 分钟默认超时内。十、小结想快速在真实多平台环境验证一个测试项目.\eng\scripts\RunHelix.ps1 -Project csproj必要时配合/p:NoBuildtrue、-HelixQueues、-TargetArchitecture想理解队列矩阵与平台分支读 eng/targets/Helix.Common.props唯一事实来源、eng/targets/Helix.props超时/依赖开关、eng/targets/Helix.targets负载构建与预命令想让测试在 Helix 上跑对优先消除对源码目录的隐式依赖确需的文件用HelixContent配合Link/LinkBase显式下发结果排查Tests 选项卡 → Helix API 下钻 work item/payload → Kusto 分析工作项耗时红线helix-matrix 被弄坏必须立即 revert 或 quarantine跳过测试必须挂 issue。【免费下载链接】aspnetcoreASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.项目地址: https://gitcode.com/GitHub_Trending/as/aspnetcore创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价