十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MongoDB 仓库的 Block-on-Red 机制:monitor_build_status 构建状态监控与 Code Lockdown 配额实践

MongoDB 仓库的 Block-on-Red 机制:monitor_build_status 构建状态监控与 Code Lockdown 配额实践 MongoDB 仓库的 Block-on-Red 机制monitor_build_status 构建状态监控与 Code Lockdown 配额实践【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo导读MongoDB 服务器本仓库GitHub_Trending/mo/mongo即 The MongoDB Database的 master 分支长期保持可发布状态至关重要。当构建失败Build Failure简称 BF数量过高、分支过红时仓库会进入所谓的Code Lockdown代码锁定限制合并方向、集中力量把构建拉回绿色。本文以仓库内 buildscripts/monitor_build_status/README.md 为骨架结合monitor_build_status模块的真实源码与配置系统讲解这一机制的动机、三级锁定策略、配额体系、Jira/Evergreen/Slack 落地实现以及如何在本地运行 CLI 复现每日报告。读完本文你将掌握Block-on-Red 的完整规则、etc/code_lockdown.yml中每一个配置项的含义以及该监控 CLI 从拉取 Jira 问题到生成 Slack 通知的完整调用链。什么是 Block-on-Red动机与策略TL;DR在 BF 数量高峰期10gen/mongomaster 分支上的代码审批与合并将被限制只允许合并有助于减少 BF、Bug、性能回退Performance Regression以及偿还技术债的变更。动机在于 master 分支必须保持稳定以便高效开发 Server并且任何时刻都要保持在距发布 30 天以内的可发布状态。一旦构建过红too red团队需要激进地把它拉回绿色。这带来两个附带收益更绿的构建让 patch build补丁构建的失败更有意义——失败不再被淹没在本身就红的环境里发布期会像日常开发一样平稳显著降低发布冲刺阶段的压力。策略是给每个团队设定配额quota当团队超过配额即进入代码锁定且锁定按影响范围分三级递进Team 级别先在小爆炸半径内停止合入解决该团队及其负责代码的可发布性风险VP 级别把配额向上汇总到某个 VP 的整个组织期望在组织内重排资源解决 BF比全局冻结更有效、破坏性更小Global 级别当全局配额被超过整个服务器组织进入锁定直到满足解冻阈值。这套三级递进逻辑在源码中体现为不同层级的阈值配置详见下文 配额体系与配置文件 一节。Code Lockdown 的影响面允许的代码变更锁定期间Code Owners 只应审批有助于关闭 BF、或帮助我们减少/避免下一次阻塞状态的变更即修复 BF、某一类 BF、Bug、性能回退等。不满足条件的 PR 可能要等到系统解除阻塞后才能被合并。功能开发全部暂停所有 feature work 在锁定期间停止除非在特殊情况下由 VP 特批。非功能开发被明确允许解决 BF 往往需要重构、模块化改进、测试改进等偿还技术债的工作这类工作在锁定期间明确允许并可合并但团队要重点评估风险。文档给出的可允许示例包括非穷尽重构组件以使其更易做单元测试通过高质量、能拦截 PR 的测试提升代码覆盖率加速开发循环降低构建时间、修复慢测试等改进提升代码质量的护栏修复 clang-tidy 警告、编译器警告等。此外还有一些风险分担原则若某团队被锁定而组织其他部分未锁定该团队应优先做能加速自己解封的工作若组织被锁定但某团队没有 BF 可处理则应平衡帮助其他团队与已识别的、解决底层 BF 问题的工作工作风险越高Staff 工程师和 Director/VP 越应参与什么能合、什么不能合的决策。Code Owner 的职责Code Owners 应加入#10gen-mongo-code-lockdownSlack 频道接收每日构建状态更新——该频道会产出每日指标并在状态发生变化时给出操作指引。进入阻塞状态时仅审批允许的变更解除阻塞后恢复常规审批。配额体系与配置文件当前监控阈值README 明确给出当前监控的阈值表QuotaTeam早于 48hVP早于 5dGlobal早于 5dHot31060Cold3740这里的早于 48h / 5d指的是团队分配时长team assignment duration的宽限期grace period一个 BF 在被分配给某团队后48 小时团队级或 5 天VP/全局级内不计入配额。实现上hot与cold的判定来自两个不同的 Jira 过滤器组合而宽限期则由每个 Issue 的团队分配时长字段过滤实现。配置文件的真实落地etc/code_lockdown.ymlREADME 声明该文件的 source-of-truth 实现为 etc/code_lockdown.yml且源码入口在 buildscripts/monitor_build_status/cli.py 中通过常量CODE_LOCKDOWN_CONFIG etc/code_lockdown.yml引用。配置文件顶层包含三个部分1.notifications通知与作用域每个通知配置包含scopes、thresholds、slack三块notifications: - scopes: - name: master branch jira_queries: hot: filter 53085 AND filter 53200 cold: filter 53085 AND filter ! 53200 thresholds: overall: # Global 级 hot: count: 60 grace_period_days: 5 cold: count: 40 grace_period_days: 5 group: # VP 级 hot: count: 10 grace_period_days: 5 cold: count: 7 grace_period_days: 5 team: # Team 级 hot: count: 3 grace_period_days: 2 cold: count: 3 grace_period_days: 2 slack: overall_scope_tags: - !subteam^S0ANBEJA4TH # database-leads # ... 各 VP / Director 的 ... 提及 message_footer: | Refer to our playbook at http://go/blockonred for details. Drill into the data using the https://jira.mongodb.org/...|Jira Dashboard.可以对照发现配置中的overall60/40宽限 5 天、group10/7宽限 5 天、team3/3宽限 2 天正好对应 README 表中的 Global、VP、Team 三档。配置文件中还保留了一个被注释掉的、面向v7.0/v8.0/v8.2版本分支的scopes示例展示如何将监控扩展到发布版本分支通过Evergreen Project in (...)过滤其thresholds使用grace_period_days: 0并设置了short_issue_data_table: True来精简 Slack 中的表格输出。scopes.name是作用域名如master branchjira_queries.hot/cold是两条 JQL 查询字符串分别用于拉取 Hot 与 Cold 两类问题。2.groupsVP 组织级分组groups把多个团队聚合到一个 VP 组织下用于计算 VP 级配额groups: - name: Durability and Availability thresholds: hot: 50 cold: 25 teams: - Workload Resilience - Replication - Storage Engines - Storage Engines - Server Integration # ... slack_tags: - U032DKCUWQ4 # mick.grahammongodb.com - VP # ...注意groups内的teams列表中的团队名必须与 Jira Assigned Teams 字段值完全一致配置文件注释明确要求 Should exactly match Assigned Teams Jira BF field value。thresholds为可选覆盖项例如 Durability and Availability 组把 hot/cold 覆盖为 50/25若组未设置thresholds则回退到notifications.thresholds.group的默认值10/7。3.teams团队级配置teams为每个团队配置 Slack 提及slack_tags与可选的阈值覆盖thresholdsteams: - name: Storage Engines slack_tags: - !subteam^S05UGLCB76U # leads-storage-engines - Leads - !subteam^S08DQ4QBP6K # storage-engines-wiredtiger-primary - Triager thresholds: # triage should route these elsewhere quickly (ie faster than the cooldown) hot: 0 cold: 0 - name: ~ Unassigned slack_tags: - !subteam^S0AHTLRQLJD # buildbaronteam for routing to appropriate team值得注意的几种阈值覆盖模式零配额Storage Engines、Storage Layer Services的 hot/cold 均为 0意味着这些团队的 triage 队列必须保持为空有任何问题都必须立刻转走。这在 CLI 中由ZERO_QUOTA_EXCEEDED消息单独处理见下文源码解析。差异化覆盖Backup - DS为 hot 1 / cold 3Query Integration为 hot 3 / cold 5SLS 系列团队统一为 hot 3 / cold 3。slack_tags为空时使用默认不提及或仅默认标签。源码解析监控 CLI 的完整调用链模块位于 buildscripts/monitor_build_status/由 5 个 Python 文件组成其 Bazel 构建目标在 buildscripts/monitor_build_status/BUILD.bazel 中声明py_library名为monitor_build_status依赖 jira-client、requests、structlog、tabulate、typer 等。入口与编排cli.py入口函数maincli.py完成四步装配从 Evergreen expansion 读取 Slack webhook URL默认 expansion 名mongo-code-lockdown-webhook创建JiraClient服务器固定为https://jira.mongodb.org认证使用JiraAuth()其凭据来自JIRA_AUTH_PAT环境变量用 code_lockdown_config.py 的CodeLockdownConfig.from_yaml_config(CODE_LOCKDOWN_CONFIG)加载 YAML 配置构造MonitorBuildStatusOrchestrator并调用evaluate_build_redness(notify)。核心编排逻辑在MonitorBuildStatusOrchestrator.evaluate_build_rednesscli.py遍历notifications中的每个通知配置对其中每个scopes用 hot/cold 两条 JQL 通过JiraService.fetch_issues拉取问题生成IssueReport调用_get_issue_counts_status计算各层级[Org] Overall、[Group]、[Team]的 hot/cold 数量及相对阈值的百分比并用tabulate渲染成文本表格调用_summarize生成摘要文本SUMMARY [scope] ...若notifyTrue将整个消息通过_send_slack_webhookPOST 到 Slack webhookcli.py否则仅打印日志。红/绿判定采用枚举CodeMergeStatuscli.py只要任一百分比超过 100 即为RED否则GREEN。百分比计算在_process_thresholds内完成hot_bf_percentage hot_issue_count / thresholds.hot.count * 100当配额为 0 而问题数大于 0 时百分比记为9999并显示为∞同时将该 scope 标记为零配额违规zero_quota_labels。摘要消息有三类由SummaryMsg枚举定义cli.pyBELOW_THRESHOLDS所有指标都在阈值 100% 以内允许全部合并THRESHOLD_EXCEEDED至少一个团队超过阈值 100%只允许审批修复 BF/Bug/性能回退的变更并列出超限 scopeZERO_QUOTA_EXCEEDED本应为空的 triage 队列当前有未解决问题需要立即路由或解决。配置模型code_lockdown_config.py该文件用 pydanticBaseModel定义了全部配置结构ThresholdConfig(count, grace_period_days)、IssueThresholds(hot, cold)、ThresholdsConfig(overall, group, team)、ScopesConfig(name, jira_queries)、SlackConfig(overall_scope_tags, message_footer, short_issue_data_table)、NotificationsConfig(scopes, thresholds, slack)、TeamConfig、GroupConfig与CodeLockdownConfig。其中CodeLockdownConfig.from_yaml_config负责读取并校验 YAML。两个值得注意的实现细节文件头注释专门说明pydantic 2 的行为变化Optional[X]不再隐式默认为None必须显式写 None否则 YAML 中省略该字段会导致校验失败——这正是TeamConfig.slack_tags、TeamConfig.thresholds等字段带 None默认值的原因get_team_thresholds/get_group_thresholdscode_lockdown_config.py实现覆盖优先缺省回退若团队/组配置了thresholds则深拷贝默认阈值并只覆盖非空项否则直接返回notifications.thresholds中的默认值。问题建模与宽限期过滤Jira 侧jira_service.py 定义了两个 Jira 自定义字段 ID——customfield_12751Assigned Teams负责团队与customfield_28352团队分配时间戳。IssueTuple.from_jira_issue把 Jira Issue 转换成(key, assigned_team, team_assignment_duration_hours)三元组负责团队取自定义字段的第一个值取不到时用UNASSIGNED_LABEL ~ Unassigned与配置文件中的~ Unassigned团队对应分配时长优先用分配时间戳计算缺失时回退到问题创建时间issue.fields.created。IssueTuple以key作为相等性与哈希依据。报告侧issue_report.py 用IssueCategoryHOT/COLD和CategorizedIssues组织问题IssueReport按assigned_team汇总。核心的get_issue_count方法issue_report.py接受min_team_assignment_duration_hours参数只统计分配时长不低于该值的 Issue——调用方传入threshold.hot.grace_period_days * 24如团队 2 天 48 小时、VP/全局 5 天 120 小时从而把宽限期内的新分配问题排除在配额之外。这解释了 README 表中older than 48h / 5d的语义。CLI 使用本地运行与 Evergreen 集成查看帮助python buildscripts/monitor_build_status/cli.py --help本地运行不发送通知Jira API 认证使用JIRA_AUTH_PAT环境变量Jira Personal Access TokenPAT。带上 PAT 运行即可在终端输出报告结果JIRA_AUTH_PATauth-token python buildscripts/monitor_build_status/cli.py按 cli.py 的定义--notify参数默认关闭default to the more quiet setting因此上面的命令不会向 Slack 频道发送通知。生产运行Evergreen 定时任务Evergreen 侧的调度脚本为 evergreen/monitor_build_status_run.sh其逻辑是激活 venv 后执行python buildscripts/monitor_build_status/cli.py并且只有非 patchis_patch ! true构建才追加--notify参数——即在主线持续集成任务中才会真正推送 Slack 通知patch 构建只做静默评估。对应 Bazel 目标monitor_build_status_run定义在 evergreen/BUILD.bazel。Slack 通知机制Slack 通知使用Devprod Test Infrastructure Slack app 的 webhook而非用户凭据以提升安全性。webhook URL 从mongo-code-lockdown-webhook这个 Evergreen expansion 读取指向#10gen-mongo-code-lockdown频道。如果未提供 webhook URL 而尝试通知_send_slack_webhook会抛出ValueError明确提示需提供--slack-webhook-url参数cli.py。消息体为{text: message}的 JSON超时 30 秒。常见问题FAQBF 仅残留在更老分支上有些团队在 master 修复了 BF但在更老分支上等待修复waiting for fixBF 仍会计入阈值。当前指引仍在演进中落地为三条标签约定若 BF 仅在早于 master 的分支上等待 backport给 ticket 打exclude-from-master-quota标签将其从 master 配额中排除预期是改善 backport 流程前的过渡方案若 BF 在 master 上失败、但不是严重 bug或纯测试问题、不影响真实客户端、不吵闹、且团队选择不修复将优先级设为P5 - Trivial并打keep-trivial标签若 BF 在更老分支失败且团队选择不 backport 修复将优先级设为P5 - Trivial并打keep-trivial-X.Y标签X.Y 为对应分支版本。对应地构建失败若不频繁发生可标记为 P5-Trivial从而不计入团队的 block merge 失败统计。测试与验证模块自带完整的单元测试位于 buildscripts/tests/monitor_build_status/Bazel 目标见 buildscripts/tests/monitor_build_status/BUILD.bazeltest_cli.py覆盖_summarize的各种分支——全绿、恰好 100%、超限、纯零配额违规、零配额与超限混合、零配额但无问题时仍为 GREEN以及组级阈值覆盖的计算验证如 DTA 组 hot50 覆盖后 25 个 hot 问题计为 50% 而非默认的 125%。test_jira_service.py验证IssueTuple的团队字段解析空列表/缺失字段回退到~ Unassigned、团队分配时长计算以及分配时间戳缺失时回退到创建时间的逻辑。test_issue_report.py验证IssueReport的增删与get_issue_count按宽限期过滤的统计逻辑。参与贡献对于任何新提案、阈值变更或应用上的疑虑README 明确要求升级到 Director/VP 层面决策并强调希望各层级都能积极建言让这一工程文化变革成功。因此etc/code_lockdown.yml中的任何配额调整都不是个人行为而应走组织评审流程。改动阈值与规则后应通过python buildscripts/monitor_build_status/cli.py --help与本地JIRA_AUTH_PATauth-token python buildscripts/monitor_build_status/cli.py验证输出再交由 Evergreen 定时任务在主线持续集成中生效。【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表