Managed 覆盖、CreateIfMissing 所有权与审计摘要

确定性绘制的技术主题封面

摘要| 重装同一个版本,为什么也要覆盖一遍?因为在长时间演进的低代码系统里,真正难处理的是资源漂移:本地改动、软删除、标识冲突和版本号对不上。本文用当前导入器源码与 143 项真实测试说明 Managed 覆盖、CreateIfMissing 所有权和墓碑保护三件事。

01|一个反直觉的选择:重装同版本也要覆盖

多数升级系统把“版本相同”当成无需处理的信号。但在长期运行的低代码系统里,版本相同并不意味着资源一致:接口引擎可能被本地改过,菜单可能被禁用甚至软删除,历史安装记录也可能丢失。这些漂移不处理,运行时就只能带着隐患继续跑。

吾码应用商城的选择是:安装动作一旦明确选择了应用包和版本,就对该包声明的 Managed 资源执行覆盖式重放——同版本也照做,用来修复资源漂移。

核心判断| 安装动作表达的是“以这个包为准”,不是“如果版本不同才更新”。

这个选择把复杂度从运行期前移到了安装期:包正文是唯一事实,导入器负责让目标端与它对齐。

02|包声明了什么,就以什么为准

导入器把 API 引擎资源分成两类策略。Managed 表示“包拥有”:决策函数只有两个结果——哈希一致时直接应用,不一致时按包覆盖。

function decideManagedApiEngineUpdate(localHash, incomingHash) {
  return localHash == incomingHash ? 'Apply' : 'ApplyPackageManagedOverwrite';
}

覆盖不是“删了重插”,而是按稳定 Key 原位更新:源码、版本、主路由与多路由、启用状态一起对齐;包内 Id 与其它资源冲突时重映射新 Id,重复的活跃键会退休,随后做严格回读,未完整落库即失败关闭。

安装时资源如何被判定与覆盖

调用链解释图(确定性渲染),依据当前导入器实现梳理。

  • Managed:包拥有,存在即覆盖,软删除会被恢复。
  • CreateIfMissing:只在完全不存在时创建,创建后归租户。
  • 审计信息:BaseHash、版本与来源摘要只用于记录,不用于阻断。

03|CreateIfMissing:一次交给租户,永远归租户

另一类资源是 CreateIfMissing,用来让租户在固定扩展点上写自己的逻辑。它的规则比 Managed 更严格:只有在记录完全不存在时才创建。

只要目标端出现过这条 Key,无论现在是启用、禁用还是软删除,都视为租户资产,导入器直接跳过,并且不会对齐 Id、源码或启用状态。

{
  "ResourcePolicies": {
    "ApiEngines": [
      { "ApiEngineKey": "platform-hdfs-upload", "Ownership": "Platform", "UpgradePolicy": "Managed" },
      { "ApiEngineKey": "platform-runtime-custom-hook", "Ownership": "Tenant", "UpgradePolicy": "CreateIfMissing" }
    ]
  }
}

墓碑保护| 软删除不是恢复信号:租户删掉的 Hook 不会被下一次安装复活。

04|Base、Local、Incoming 只作审计

旧的一版式升级会在本地摘要与基线不一致时报冲突,甚至整包回滚等待人工处理。结果是:包越升级,越容易被本地定制卡住。

当前实现把这三个摘要降级为审计信息:Managed 决策不再读取它们,也不再存在“保留较新版本”的分支。发布器仍会计算通用基线,但导入器的日志只把它当作参照。

四种资源状态的不同处理路径

状态边界解释图(确定性渲染),四种资源状态的路径并不相同。

取舍| 用“包正文优先”换掉了“本地差异优先”,代价是本地手改 Managed 资源会在下一次安装被覆盖——因此 Managed 与 CreateIfMissing 的边界必须写清楚。

05|种子数据与元数据:覆盖也要有限度

覆盖式重放不等于整包覆盖一切。数据种子走 INSERT_IF_MISSING:以稳定业务键判断存在性,已配置的行不会被同 Id 的包内数据覆盖;只有分类、描述与排序这类元数据允许刷新。

导入器还要求:未声明的 upsert 被拒绝;固定官方包快照、版本与大小校验失败时失败关闭;拼装包来源不可信时不执行覆盖。

  1. Managed:按包覆盖并恢复软删除。
  2. CreateIfMissing:存在即跳过,墓碑不被复活。
  3. 种子数据:按稳定键幂等插入,不覆盖已配置值。
  4. 快照与身份校验:不通过则失败关闭,不带病安装。

06|把结论交给测试

这些规则不是口头约定。仓库里有四个可运行的 Node 测试文件,覆盖覆盖决策、墓碑保护、固定版本快照与安装版本状态。

四个测试文件的执行记录

本地执行记录(确定性渲染):143 项断言全部通过。

本文引用导入器与升级入口的当前源码区域,并执行了四项真实测试:115 + 12 + 8 + 8 项断言全部通过(exit 0)。同时保留了一个公开矛盾:应用商城文档仍写着旧的三方回滚描述,而导入器、更新日志与官方 Skill 都已改为“选定包 Managed 覆盖”,运行时以代码为准。

07|交付边界

需要写清的边界有三条:源码与测试证明的是当前实现;测试在本地工作区执行、可复现;线上行为仍取决于具体部署版本的导入器版本与快照能力,证据文件没有把它表述为生产结论。

交付边界| Managed 覆盖、CreateIfMissing 只补缺、Base/Local/Incoming 只审计;软删除墓碑归租户。

把包正文当成唯一事实,把本地差异当成审计信息——低代码平台的升级才不会被历史定制拖住。

内容说明:文中已标注的概念图由AI生成;源码与实测证据均来自当前工作区。竖卡的准确文案由确定性排版叠加,封面、调用链图、状态边界图与实测图均由确定性程序绘制,图注已分别说明。

Logo

宁波官方开源宣传和活动阵地,欢迎各位和我们共建开源生态体系!

更多推荐