拓冰建站拓冰建站
首页 / 资讯中心 / 正文

DeepSeek Harness 并行 GitHub CI 门禁实战:分片拓扑、有界调度与产物边界设计

DeepSeek Harness 并行 GitHub CI 门禁实战分片拓扑、有界调度与产物边界设计【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harnessDeepSeek Harness 是一个以 Everything is a Plugin 为理念的多包 TypeScript 工作区其无密钥 CIKeyless CI包含类型检查、lint、文档新鲜度、覆盖率、快照重放、构建、发布卫生与冒烟测试等大量相互正交的门禁。本文基于仓库归档的 Agent Note.agents/notes/archived/process/2026-07-06-parallel-github-ci-gates.md完整复盘该项目如何把一条串行命令链改造为显式分片 有界调度的并行 CI 拓扑并结合当前仓库中仍保留的调度器源码scripts/run-gates.ts剖析其底层实现。读完本文你将掌握在大型 monorepo 中如何权衡 job 粒度和编排开销、如何设计带依赖约束的并行门禁调度器以及为什么产物lib/边界必须由显式契约而非包管理器打包来守护。问题正交门禁如何从串行求和走向编排瓶颈仓库中大部分无密钥 CI 门禁彼此正交——typecheck、lint、文档新鲜度、覆盖率、快照重放、构建、包发布卫生、demo 冒烟、已构建二进制冒烟失败的原因各不相同也不需要彼此的运行时状态。于是出现了两个极端的成本模型一条有序命令链工作流墙钟时间等于所有门禁耗时之和反馈周期随门禁数量线性增长每个短叶子一个独立 GitHub jobcheckout、Node 环境设置、pnpm restore、安装被反复执行直到编排开销成为新瓶颈。随着 workspace 不断增大项目原有的宽车道拆分broad-lane split不再能维持两者的平衡。归档笔记记录了 PR #404 合并时的实测数据平台Job实测耗时Linux静态门禁148 秒Linux覆盖率195 秒Linux快照94 秒Linux产物230 秒Windows静态门禁251 秒Windows产物482 秒进一步定位到三个具体病灶包管理器打包每个包执行一次pack主导了两个产物验证器覆盖率在仅运行源码的套件前无谓地重建输出属于纯延迟CPU 密集型门禁在静态与覆盖率车道内互相争抢资源。值得强调的一点是产物边界仍然承重publint、verify-node-next-types、已编译不变量加载、已构建二进制冒烟都必须消费构建产出的lib/目录。分片可以让它们在各自车道内并行但不能把消费方调度到构建之前也不能用源码执行去替代它们对已发布产物的验证信号。决策总览历史拓扑、性能目标与完整性判据先明确这篇笔记的定位它描述的生产拓扑已经是历史后续被 [基于证据采用更大的托管 runner]2026-07-22-evidence-based-larger-hosted-runners.md该决策移除了分片选择器与工作流 job取代。保留这份笔记的价值在于解释早期拓扑为何被实现其中的权衡分析对任何大型仓库的 CI 设计仍有参考意义。该拓扑确立了三条关键原则性能目标是观测值不是取消截止时间。.github/workflows/ci.yml 将非 Windows job 的 1 分钟、Windows job 的 3 分钟视为观测所得的性能目标observed performance targets而非取消cancellation期限。托管 runner 存在波动应当保留完整的计时证据和有用的失败日志而不是取消一个本来正确的门禁。优化的车道清单不能成为自身完整性的唯一判据。串行跨平台 CI 参考2026-07-21-serial-cross-platform-ci-reference.md会在 Linux、macOS、Windows 上独立运行完整的、未分片的主 Node 聚合primary Node aggregate作为完整性 oracle。GitHub 提供显式分片名称调度由脚本负责。昂贵的门禁族由scripts/run-gates.ts这个通用有界调度器统一编排。调度层实现run-gates.ts 的有界并行语义scripts/run-gates.ts 是整套拓扑的中枢负责把命名聚合named aggregate展开为带依赖图的门禁列表再以有界并发执行。从源码可以看到它对外暴露的聚合模式Modeci-primary / ci-linux-primary / ci-static / ci-lint-contracts-ready ci-coverage / ci-snapshot / ci-artifacts / ci-consumers ci-windows-blocking / ci-windows-complete / ci-windows-observational node-compat / check-all / hygiene / doc-sync / doc-quick其中ci-static、ci-coverage、ci-snapshot、ci-artifacts正是早期分片拓扑对应的昂贵门禁族入口而ci-windows-*系列体现了 Windows 与 Linux 不同的调度策略。调度器最核心的数据结构是Gate接口它把依赖关系建模为两个不同语义的字段needs必须通过passed之后该门禁才能启动——对应产物消费方必须在构建之后这类硬约束after只需已结算passed/failed/skipped 均可之后即可启动——用于让可能失败的读者先落定这类软约束例如 HMR web 测试会重写共享lib/与apps/web/dist/树所有构建产物读取方都必须在它启动前结算且即使某个读取方失败也要保留 web 诊断输出。其余字段包括id聚合内唯一、label展示名、command/args/displayCommand、env、allowFailure保留失败可见性但不阻塞聚合、streamOutput实时输出而非缓冲到结束。调度前会执行validateGateGraph严格校验空图、重复id、引用不存在的依赖、依赖环都会直接抛错调度循环中needs依赖失败的门禁会被标记为skippeddependency failed or skipped: ...而不是被启动。并发控制也完全参数化defaultConcurrency对ci-consumers使用门禁总数作为并发消费者互不争用 CPU对check-all、hygiene、doc-sync、doc-quick等本地模式则按 CPU 数封顶为 4——因为多个文档门禁各自构建完整的ts.Program在大机器上不设上限会用墙钟换内存爆炸。所有模式都支持通过环境变量DSH_GATE_CONCURRENCY覆盖为任意正整数。收尾时printSummary汇总passed/failed/skipped对非阻塞门禁输出NON-BLOCKING FAILED前缀并逐条打印exit code、signal、spawn 错误等失败事实避免一种失败原因掩盖另一种。静态门禁分片七类归属与字母分区 lint在早期拓扑中静态门禁由scripts/static-shards.ts维护该文件随更大 runner 决策被移除当前仓库中已不存在可从 scripts/ 目录清单确认。其职责是把静态门禁按归属ownership划分为七类基础foundation、文档类型documentation-type、API 契约API-contract、目录catalog、正文prose、文档投影documentation-projection、文档构建documentation-build并拒绝缺失或重复的门禁分配——分片脚本自带完整性校验而不是把是否漏分片留给 CI 失败去发现。Lint 是静态门禁中最需要并行化的部分其分区策略体现了平台差异Linux使用互不重叠的A-C、D-M、N-S、T-Z四个包源码package-source与包测试package-test车道Windows使用完整的包源码与包测试车道不按字母拆分。两者的共同点是都包含一个从.开始的仓库补集repository complement确保新增的顶层目标不会消失在分片之间并各自承担唯一一次跨文件重复duplication检查。工作流还会把每个不可变 ESLint 缓存的键绑定到其所属 lint 分片保证分片间互不污染缓存。覆盖率分片每个包恰好一个车道覆盖率由scripts/coverage-shards.ts维护约束是每个 workspace 包恰好分配给一个源码覆盖率车道exactly one source-coverage lane。实现上有两个容易被忽略的细节目录过滤器保留尾部分隔符。原因是 Vitest 的位置过滤器按子字符串匹配若不保留尾部/前缀同名的相邻目录会被误纳入。覆盖率车道不先执行构建。每个车道只包含其拥有的源码文件并重复运行穷尽式伴随拓扑测试exhaustive companion topology test从删除了所有生成lib/的树开始完整覆盖率套件依然通过——这与构建前置只是纯延迟的实测结论相互印证。快照重放两个多文件车道 八个场景分区快照snapshot replay由scripts/snapshot-shards.ts维护清单采用两个显式多文件车道外加对大型 ACPAgent Client Protocol文件的八个场景分区脚本的配套测试会枚举快照配置允许的每个文件防止新快照落入无人认领状态。快照 job 的流水线设计充分利用了等待时间在 Linux runner 准备 Bubblewrap 沙箱的同时安装依赖随后构建已发布运行时shipped runtime最后只运行分配给自己的重放面。套件保持五个子进程的有界并发因为重放的大部分墙钟时间都花在等待子进程协议 I/O 上而不是 CPU 上。此外fixture测试前置数据守卫会在每个分区中检查完整的 ACP 场景表避免分片导致某类 fixture 在部分分区里缺失验证。文档门禁冷启动成本决定车道形态冷启动的独立文档类型检查documentation typecheck会重建完整的项目引用图project-reference graph因此文档类型车道只构建一次然后用这些声明去检查 Markdown 代码块。Linux 文档车道采用 VitePress 的 MPA 构建从而在观测所得的非 Windows 性能目标内保留页面渲染与死链接验证而阻塞式blockingWindows 构建与生产站点车道各自独立分别保留已生成包与已发布站点检查刻意避免把两条关键路径塞进同一个 job。产物门禁两条车道与免打包发布验证产物验证被拆成两条车道每条车道都先自行构建再运行消费方一条元数据车道负责publint、NodeNext 声明与已编译不变量加载另一条负责已构建二进制冒烟。重复一次短构建会消耗 runner 分钟但换来的是无上传/下载依赖、每个 job 关键路径有界——这正是重复构建 vs 共享一次构建权衡中的明确选择。两条车道背后的验证器本身是早期拓扑最值得借鉴的部分scripts/publint-all.ts在进程内调用 publint 支持的 API对一个内存中的发布视图in-memory publication view执行校验。这个视图由每份清单manifest声明的files字段和 npm 强制元数据文件构成从而既保留了workspace 文件 vs 已发布文件的区分又避免了为 103 个包各 spawn 一次包管理器pack命令。scripts/verify-built-package-invariants.mjs则把经过结构验证、由清单声明的lib/文件暂存到真实包目录之下staging再通过纯 Node 与 Cordis Loader 规范化导入已编译的自引用self-reference任何触及未声明运行时分片的伴随项companion都会失败——也就是说发布验证不是看看文件在不在而是真的把包当包导入一次。兼容性车道与主车道分工兼容性compatibility车道在每条声明支持的 Node 版本线上运行源码 worker 与 Zstandard 运行时冒烟source-worker-smoke、jsonl-zstd-smoke等见 scripts/run-gates.ts 中nodeCompatSmokeGates而 TypeScript 对源码图的检查只在专用的主 Node 24 车道执行一次。决策理由很直接在运行时兼容性 job 里重复同样的编译器分析只增加耗时却不产生任何运行时特有信号——Node 特有行为已经由冒烟测试覆盖。缓存、状态与 Windows 调度工作流层面的收尾设计包括缓存 pnpm store每个 ESLint 缓存键绑定所属 lint 分片Windows 测量保留原生 PowerShell不做 shell 转义转换对外保留一个聚合的all checks passed状态用于分支保护。Windows 的调度哲学与 Linux 不同Windows 复用三个穷尽式 lint 分区并在共享 runner 设置后把基础/目录/正文与文档类型/API 契约门禁组合在后台只有调度方式与 Linux 分区不同检查内容一致。Windows 构建与生产站点验证保持阻塞blocking而更宽的 Windows 静态、lint、产物矩阵保持观测性observational——非阻塞门禁失败不阻止合并但计时与日志会完整保留。这与性能目标而非取消期限的原则一脉相承。曾考虑的替代方案及其取舍方案优点被否定的原因保留宽车道工作流 YAML 最少保留已实测的多分钟反馈周期每个叶子门禁独立 job扇出最大化短生成器/正文检查准备 runner 的时间超过检查本身上传一次构建给消费方避免重复编译上传/下载与依赖调度拉长墙钟干净构建足够短可在有界车道内重复两个发布门禁都保留 pnpm pack清单选择委托给 pnpm重复启动 200 包管理器进程结构门禁 发布视图 fixture 让清单契约显式化且能对磁盘上有但未发布的依赖直接失败覆盖率前保留构建提供生成输出源码套件不再消费它干净树覆盖率证明它只是纯延迟每个 Node 版本都跑 typecheck覆盖面更广重复编译器工作兼容性冒烟已覆盖 Node 特有加载与压缩行为后果与演进分片不是仓库契约最后需要厘清这份归档笔记的当前效力笔记中描述的分片清单与矩阵 job不属于当前仓库契约。取代它的更大 runner 决策在单个进程中保留完整主清单并以串行套件作为独立完整性判据从源码结构看static-shards.ts、coverage-shards.ts、snapshot-shards.ts已不在 scripts/ 目录中scripts/run-gates.ts 则演化为当前仍在使用的聚合调度器。优化后的发布验证器依赖由verify-package-invariants强制执行的清单files契约。如果发布规则超出该契约结构门禁与两个暂存视图publint 的内存视图、built-package-invariants 的暂存导入必须一起演进。兼容性 job 的语义被收窄但更诚实它们不再声称 TypeScript 在每个 Node 运行时下都被执行而是证明Node 22、24、26 上对运行时敏感的源码加载唯一的源码图类型检查由主运行时承担。这份笔记对大型 monorepo 的 CI 设计给出了一个可复用的方法论用显式分片脚本保证清单完整性、用带needs/after双语义的有界调度器控制依赖与并发、用结构化的发布契约替代昂贵的包管理器打包、用观测性非阻塞车道换取完整证据——并行化的最终目的不是消灭失败而是让每次失败都以最快的速度和最完整的证据被看到。【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门