尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Bytebase Plan Check Run 运行时派生重构:从冗余存储到按需计算的配置推导

发布时间:2026/9/15 2:28:39

资讯中心
01
ARTICLE

Bytebase Plan Check Run 运行时派生重构:从冗余存储到按需计算的配置推导

Bytebase Plan Check Run 运行时派生重构:从冗余存储到按需计算的配置推导
Bytebase Plan Check Run 运行时派生重构从冗余存储到按需计算的配置推导【免费下载链接】bytebaseDatabase governance built for humans and agents — controlling changes and access across every major database.项目地址: https://gitcode.com/GitHub_Trending/by/bytebase导读本篇文章深入解析 Bytebase 开源仓库中的一份核心设计文档docs/plans/2026-01-05-plan-check-run-runtime-derivation.md如何将 Plan Check Run计划检查运行的配置从随运行持久化一份完整副本重构为运行时从关联 Plan 实时推导。读完本文你将理解 Bytebase 数据库变更治理链路中计划检查的数据模型演进、config/payload两列的迁移清理方案以及派生函数在调度器Scheduler中的实际调用流程可直接对照仓库源码继续深入。一、背景与动机为什么不再存储一份自包含配置Bytebase 的 Plan Check计划检查是变更审批前的自动校验环节例如对 SQL 进行语句评审Statement Advise、生成摘要报告Statement Summary Report以及在开启 gh-ost 在线变更时执行 ghost 同步检查。在重构之前每次计划检查运行时系统会通过getPlanCheckRunFromPlan()从 Plan 复制一份配置存入 Plan Check Run 记录中形成自包含的持久化副本。该设计文档指出这种做法带来三个问题简化代码需要移除getPlanCheckRunFromPlan()中的配置复制逻辑减少存储避免存储与 Plan 重复的冗余数据防止过期Plan Check Run 配置一旦与 Plan 脱钩就可能与 Plan 的实际状态不同步staleness导致检查基于过时配置执行。重构前的数据冗余设计文档以表格清晰刻画了重构前plan_check_run表中重复存储的字段字段在 Plan 中的位置在 Plan Check Run 中的位置sheet_sha256ChangeDatabaseConfigCheckTargetenable_prior_backupChangeDatabaseConfigCheckTargetenable_ghostChangeDatabaseConfigCheckTargetghost_flagsChangeDatabaseConfigCheckTargettargetsSpec 级别按每个CheckTarget展开其中config列以 JSONB 存储PlanCheckRunConfig内含上述重复字段而payload列则始终未被使用reserved。二、核心洞察一运行一 Plan 的唯一性约束该重构成立的前提是设计文档强调的一个关键约束每个 Plan 只有一个 Plan Check Runplan_id上存在唯一约束。当计划检查被重新执行时旧的运行会被直接替换。由此可以推出三点结论无需保留历史配置旧运行被替换历史配置没有保留价值结果自带目标信息检查结果中包含 target 信息天然自描述配置可以从当前 Plan 状态推导由于运行始终与最新 Plan 关联运行时推导必然拿到最新状态。这三点共同保证了运行时派生不会引入正确性问题——检查永远基于 Plan 的最新配置执行反而从根本上消除了配置过期风险。三、数据模型变更裁剪plan_check_run表移除的列config列JSONB存储PlanCheckRunConfigpayload列未使用预留保留的列列说明id主键created_at/updated_at创建/更新时间plan_id指向 Plan 的外键status运行状态RUNNING / DONE / FAILED / CANCELEDresultJSONB存储PlanCheckRunResultProto 层变更设计文档要求对proto/store/store/plan_check_run.proto进行如下清理删除PlanCheckRunConfigmessage删除CheckTargetmessage仅用于 config如果 API 层向客户端暴露了 config则同步更新 API protoproto/v1/plan_service.proto。对照当前仓库的 proto/store/store/plan_check_run.proto该文件已只保留PlanCheckRunResult含Result、SqlSummaryReport、SqlReviewReport等以及ChangedResources系列 messagePlanCheckRunConfig与CheckTarget均已不在其中——证明上述清理已落地。同时PlanCheckRunResult.Result中保留了target格式为instances/{instance}/databases/{database}、type、sheet_sha256字段这与设计文档结果自带目标信息、结果自描述的结论一致。Store 层变更从PlanCheckRunMessage中移除Config字段更新 CRUD 操作使其不再读写 config/payload 列。四、运行时派生纯函数式的配置推导派生结构体设计文档给出的核心方案是getPlanCheckRunFromPlan()不再创建并持久化 config而是返回一个内存中的结构体type DerivedCheckTarget struct { Target string // database resource name SheetSHA256 string // from plan spec EnablePriorBackup bool EnableGhost bool GhostFlags map[string]string Types []storepb.PlanCheckType }在仓库的实际实现中该结构体以 backend/runner/plancheck/check_target.go 中的CheckTarget落地字段与设计一致并补充了注释说明Target规范化的数据库资源名形如instances/{instance}/databases/{database}或projects/{project}/instances/{instance}/databases/{database}SheetSha256SQL sheet 的内容哈希EnablePriorBackup是否在迁移前开启备份EnableGhost是否启用 gh-ost 在线迁移GhostFlagsgh-ost 的配置参数Types针对该目标需要执行的计划检查类型。Executor 流程设计文档定义了重构后的执行流程获取 Plan Check Run包含plan_id、status通过plan_id获取 Plan调用派生函数得到 targets 与 config针对每个 target使用派生出的 config 执行检查将结果写入result字段。仓库中的实际调度实现对照 backend/runner/plancheck/scheduler.gorunPlanCheckRun()完整实现了上述流程通过s.store.GetPlan()按projectID planUID获取 Plan校验plan.Config.GetApprovalInputVersion()与运行声明的approvalInputVersion一致否则将该运行标记为 CANCELEDstale plan check run——这是并发场景下防止旧运行写入过期结果的兜底机制获取 Project若项目已归档project.Deleted则取消运行调用GetDatabaseGroupForPlan()见 backend/runner/plancheck/database_group.go在需要时解析数据库组并展开匹配的数据库列表调用DeriveCheckTargets()在运行时推导 targets遍历 targets通过s.executor.RunForTarget()接口定义见 backend/runner/plancheck/executor.go执行检查并聚合结果依据执行结果调用UpdatePlanCheckRunIfApprovalInputVersion()将运行标记为 DONE / FAILED / CANCELED结果写入PlanCheckRunResult运行结束后向ApprovalCheckChan发送信号触发审批查找approval finding进而推动 rollout 创建。值得注意的是步骤 8 表明 Plan Check 是审批链路的前置闸门只有当检查 DONE 之后审批与发布流程才会继续推进。五、派生函数的实现细节组展开、CI 采样与 gh-ost 识别设计文档特别强调派生逻辑本身保持不变数据库组展开、CI 采样。仓库中的 backend/runner/plancheck/derive.go 展示了完整的派生实现它同时印证并深化了设计1. 两个入口两种采样策略func DeriveCheckTargets(ctx context.Context, s *store.Store, project *store.ProjectMessage, plan *store.PlanMessage, databaseGroup *v1pb.DatabaseGroup) ([]*CheckTarget, error) { return deriveTargets(ctx, s, project, plan, databaseGroup, true) } func DeriveReviewTargets(ctx context.Context, s *store.Store, project *store.ProjectMessage, plan *store.PlanMessage, databaseGroup *v1pb.DatabaseGroup) ([]*CheckTarget, error) { return deriveTargets(ctx, s, project, plan, databaseGroup, false) }DeriveCheckTargets应用 CI 采样。Plan Check 本质是 CI 校验采样用于控制检查成本DeriveReviewTargets不采样。评审运行review run的 DONE 意味着每一个 (spec, target) 单元都被评估过必须看到完整目标集。2. 目标展开逻辑deriveTargets()遍历plan.Config.Specs按 spec 类型分支处理CreateDatabaseConfig创建数据库不执行计划检查ChangeDatabaseConfig若Release ! 发布场景则跳过计划检查否则若目标列表中唯一目标恰为数据库组名则用databaseGroup.MatchedDatabases展开否则直接使用Targets列表在applySampling为 true 且project.Setting.GetCiSamplingSize() 0且目标数超出采样上限时截断到前samplingSize个。3. gh-ost 指令解析派生函数会通过getSheetContent()依据SheetSha256读取 SQL sheet 内容调用ghost.IsGhostEnabled()判断是否启用 gh-ost若启用则调用ghost.ParseGhostDirective()解析 gh-ost 指令得到GhostFlags最终根据是否启用 gh-ost 决定追加PLAN_CHECK_TYPE_GHOST_SYNC检查类型types : []storepb.PlanCheckType{ storepb.PlanCheckType_PLAN_CHECK_TYPE_STATEMENT_ADVISE, storepb.PlanCheckType_PLAN_CHECK_TYPE_STATEMENT_SUMMARY_REPORT, } if enableGhost { types append(types, storepb.PlanCheckType_PLAN_CHECK_TYPE_GHOST_SYNC) }4. 数据库组解析backend/runner/plancheck/database_group.go 中的GetDatabaseGroupForPlan()负责识别 Plan 的 change-database spec 是否指向数据库组 → 查询数据库组 → 列出项目下全部数据库 → 通过utils.GetMatchedDatabasesInDatabaseGroup()计算匹配数据库并填充MatchedDatabases。注释特别提醒allDatabases必须是完整未过滤的数据库列表否则组展开会静默不完整。六、迁移脚本一次安全的在线 DDL设计文档给出的迁移 SQL 为ALTER TABLE plan_check_run DROP COLUMN config; ALTER TABLE plan_check_run DROP COLUMN payload;该迁移已在仓库中落地为 backend/migrator/migration/3.14/0021##remove_plan_check_run_config_payload.sql内容与设计完全一致。由于两个列中payload本就未使用、config可由 Plan 在运行时重新推导删除操作不涉及数据回填或转换属于低风险的列裁剪迁移。七、保持不变的部分设计文档明确列出了重构中不变的边界确保改动不扩散PlanCheckRunResultproto 保持不变按 target 存储实际检查结果Plan Check Run 的状态生命周期不变RUNNING → DONE / FAILED / CANCELED派生逻辑本身不变数据库组展开、CI 采样每个 Plan 一个 Plan Check Run的唯一约束不变。这些不变项意味着该重构是纯内部架构优化对外部 API 消费者、状态机与检查语义均无影响风险被严格控制在存储层与运行器的实现细节内。八、涉及文件一览按设计文档与仓库现状对照设计文档给出的改动清单如下结合当前仓库可以看到各层的实际落点层文件变更Protostoreproto/store/store/plan_check_run.proto移除PlanCheckRunConfig、CheckTarget已落地当前仅保留PlanCheckRunResultProtoAPIproto/v1/plan_service.proto若向客户端暴露 config 则移除迁移backend/migrator/migration/3.14/0021##remove_plan_check_run_config_payload.sqlDROPconfig、payload列Storebackend/store/plan_check_run.go移除Config字段更新 CRUDAPIbackend/api/v1/plan_service.go简化创建逻辑抽出派生函数Runnerbackend/runner/plancheck/scheduler.go运行时获取 Plan 并推导 targetsExecutorsbackend/runner/plancheck/*.go接收派生出的配置CheckTarget九、测试佐证派生语义的可验证性重构后的派生逻辑由单元测试直接守护。backend/runner/plancheck/derive_test.go 中的TestDeriveReviewTargetsSkipsCISampling构造了一个含 3 个目标的 PlanCiSamplingSize: 1断言DeriveCheckTargets仅返回 1 个目标——plan checks apply the CI sampling limitDeriveReviewTargets返回全部 3 个目标——review must evaluate every target regardless of CI sampling。该测试同时验证了设计文档派生逻辑本身保持不变与CI 采样两条核心承诺是理解派生语义的最佳入口。总结plan-check-run-runtime-derivation是一次典型的以数据模型简化换取运行时计算的架构演进借助一 Plan 一运行的唯一约束Bytebase 将计划检查的配置从持久化副本改为纯函数派生删除了config/payload两列把getPlanCheckRunFromPlan()收敛为DeriveCheckTargets/DeriveReviewTargets两个派生入口并在调度器中按取运行 → 取 Plan → 派生目标 → 执行检查 → 写回结果的流程运行。对于想要理解 Bytebase 计划检查、审批门禁与 gh-ost 集成链路的开发者backend/runner/plancheck 目录下的derive.go、scheduler.go、check_target.go与配套测试是最直接的阅读起点。【免费下载链接】bytebaseDatabase governance built for humans and agents — controlling changes and access across every major database.项目地址: https://gitcode.com/GitHub_Trending/by/bytebase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。