Files
qinglong/docs/adr/ADR-0225-postgresql-serializable-plugin-package-workflow-admission.md

4.7 KiB
Raw Permalink Blame History

ADR-0225PostgreSQL Serializable Plugin Package Workflow 准入

  • 状态:Proposed
  • 日期:2026-07-30
  • 关联 RFCQL-RFC-0001 D-03、D-12、D-144、D-207、D-212
  • 关联 ADRADR-0156、ADR-0158、ADR-0222、ADR-0223、ADR-0224

背景

SQLite v41 已证明 generation-bound Workflow plan 可以在一个 BEGIN IMMEDIATE 事务中原子展开。Cluster 不能简单把这个实现翻译成若干 PostgreSQL autocommit automation start guard 中的 publisher signer advisory lock、publication/install/ lifecycle 行锁、quarantine/revocation absence 判断,以及 Run/StepRun 写入必须属于同一 transaction。否则安全事实仍可能穿越检查与提交。

跨方言审计还发现 runtime admission 原先生成约 64 字节 RunEvent ID,而 PostgreSQL run_events.idvarchar(36)plan 的 Run ID 也曾允许 128 字节。公共契约现已 收紧为最多 36 字节 Run ID,并生成最多 36 字节 admission/Step RunEvent ID StepRun/mutation identity 继续允许 128 字节。这样无需扩大既有 Run 外键闭包。

决策

1. 使用同一 SERIALIZABLE transaction

Cluster adapter 必须在一个专用 connection 上执行:

  1. BEGIN ISOLATION LEVEL SERIALIZABLE
  2. durable exact replay lookup
  3. 调用既有 plugin_package_automation_start_allowed
  4. 在事务内复验 exact publication Workflow 与 materialized Task source digest
  5. 原子写 Run、全部 StepRun、RunEvent、StepRunMutation、admission/step ledger
  6. COMMITserialization failure 作为可安全重试的 unavailable,不在内部无界重试。

现有 start guard 取得的 pg_advisory_xact_lockFOR SHARE 锁会一直保持到该 transaction 结束。SERIALIZABLE 的 predicate conflict 负责拒绝 guard 后插入的 quarantine/revocation 等 phantom;不能降为默认 Read Committed。

2. runtime 只获得窄表权限

pg-0045 只向 ql3_runtime 授予 admission 两表的 SELECT, INSERT,以及既有 Run/StepRun execution 写权限;不向 runtime 开放 quarantine、publisher receipt 或 lifecycle mutation。manager、package-manager、package-executor、worker-ingress 不得 写 admission ledger。

3. exact replay 先于 current guard

与 SQLite 相同,已提交 exact plan 必须返回原 receipt,即使 Package 后来 withdrawn 或 quarantined。新的 plan 才检查 current guard。相同 planId/runId/receipt/StepRun/ event/mutation identity 绑定不同内容时 conflictCOMMIT response loss 只能 inspect durable winner。

admission ledger 对 runtime 是 append-only(仅 SELECT, INSERT);重放读取不得使用 FOR UPDATE/FOR SHARE,否则 PostgreSQL 会要求 UPDATE 权限。并发竞争由 SERIALIZABLE、唯一约束和事务级 start guard fence 收敛,不为不可变行扩大权限。

4. 不在事务内执行外部副作用

admission 只展开 durable DAG,不创建 Attempt、不 claim Worker、不调用 Executor。 后续 caller-driven frontier 在新事务中推进 ready Step,避免长事务、连接占用和锁 等待随 Task 执行时间增长。

接受门

  1. pg-0045 schema、capability、checksum、权限与 readiness
  2. mocked repository contract 与真实 PostgreSQL exact replay/collision/guard/ serialization rollback
  3. runtime 角色可准入但不能直接读取安全 receipt 或调用管理 mutation
  4. PostgreSQL 18 physical streaming HA 下 admission ledger、Run/StepRun 和 receipt 经 remote_apply、promotion、旧主 fencing、pg_rewind、fresh replicas 保持;
  5. 无 image pull 的 HA 重跑,且不新增 package、依赖、daemon/timer/watcher。

当前验证

  1. pg-0045 已把 control-core 推进至 v44,并增加两张 admission ledger、受审 snapshot function、显式约束/索引、Drizzle schema、manifest/checksum 与六角色 readiness
  2. PostgreSQL repository 使用同一 connection 的 SERIALIZABLE transaction,完整 durable evidence exact replay 优先于 mutable guardmock 与 package 全量为 217 pass、1 条无测试 URL 条件 skip
  3. runtime 对新表只有 SELECT, INSERT,真实故障注入进一步证明 replay 读取不能使用 FOR SHAREmanager/admin/package-executor/worker-ingress 无该 authority
  4. PostgreSQL 18.4 arm64 physical HA 在 QL3_HA_SKIP_IMAGE_PULL=true 下完整通过:admission、2 个 StepRun、Event/mutation 与 receipt 经 remote_apply、timeline 1→2、旧主 fencing、promotion、 pg_rewind 和 fresh replicas 保持;
  5. Workflow admission 的 atomic、exact replay、publisher revocation fence、 runtime-only 与 survives-promotion 五项 gate 以及总 passed 均为 true
  6. 后续 frontier 边界见 ADR-0226。