mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-22 10:32:40 +08:00
feat(ql3): establish 3.0 incubation baseline
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
# ADR-0226:有界 Plugin Package Workflow Frontier
|
||||
|
||||
- 状态:Proposed
|
||||
- 日期:2026-07-30
|
||||
- 关联 RFC:QL-RFC-0001 D-03、D-207、D-212
|
||||
- 关联 ADR:ADR-0156、ADR-0223、ADR-0224、ADR-0225
|
||||
|
||||
## 背景
|
||||
|
||||
ADR-0223 至 ADR-0225 已把 generation-bound Workflow DAG 原子展开为一个
|
||||
runtime-owned Workflow Run、全部 StepRun、Event/mutation 与 admission receipt。
|
||||
准入后的 Workflow Run 固定为 `running`,而 Task root StepRun 为 `ready`、其余
|
||||
StepRun 为 `pending`。
|
||||
|
||||
首次 PostgreSQL HA 重跑暴露出一个恢复边界错误:通用 Cluster Run recovery 把没有
|
||||
RunAttempt 的 Workflow 聚合 Run 识别成孤儿执行。该判断对普通 Task Run 成立,但
|
||||
Workflow Run 本身是编排聚合,不应直接进入普通 Task dispatcher,也不应伪造一个
|
||||
RunAttempt 或终态绕过恢复。
|
||||
|
||||
同时,低配 Edge 不能为每个 dormant Workflow 建立 timer、watcher 或内存队列;Cluster
|
||||
多副本也不能依赖进程内 frontier。
|
||||
|
||||
## 决策
|
||||
|
||||
### 1. 通用恢复器排除 Workflow 聚合
|
||||
|
||||
PostgreSQL 通用 recovery source 必须排除
|
||||
`trigger_type='plugin_package_workflow'`。这不是忽略孤儿工作,而是明确 ownership:
|
||||
|
||||
- 普通 Task Run/RunAttempt 继续由既有 Cluster recovery 处理;
|
||||
- Workflow 聚合 Run 只由专属 Workflow frontier/recovery 处理;
|
||||
- Workflow 的 Task Step 后续仍必须通过既有 RunAttempt/Executor fence 启动,不能把
|
||||
聚合 Run 作为普通 Task 分发。
|
||||
|
||||
### 2. 纯 frontier 契约留在现有 runtime-core
|
||||
|
||||
新增显式 subpath
|
||||
`@qinglong/runtime-core/plugin-package-workflow-frontier`,不新增 workspace package、
|
||||
第三方依赖、进程或连接。一次 resolution 只接受:
|
||||
|
||||
- exact normalized immutable plan;
|
||||
- exact runtime-owned `plugin_package_workflow` Run fence;
|
||||
- 与 plan 一一对应的最多 128 个 durable StepRun;
|
||||
- 单调的存储 observation time。
|
||||
|
||||
契约对完整 StepRun 集合、Run/Project/Workflow/publication identity、Task
|
||||
definition ref/digest 和 record digest 失败关闭。
|
||||
|
||||
### 3. 一次纯计算收敛依赖 frontier
|
||||
|
||||
resolution 使用确定性规则:
|
||||
|
||||
1. pending Step 的所有 `needs` 都为 `succeeded` 时生成 `pending → ready` mutation;
|
||||
2. 任一祖先为 `failed|skipped|cancelled|timed_out` 时,依赖失败可在同一 pass 传递,
|
||||
下游生成 `pending → skipped`,result code 固定为
|
||||
`dependency_not_succeeded`;
|
||||
3. mutation 按 canonical Step key 顺序绑定连续 Run version/event sequence;
|
||||
4. frontier event ID 不超过双方言共有的 36 字节,mutation ID 由 plan、StepRun
|
||||
identity/version 与目标状态做 domain-separated digest;
|
||||
5. resolution 返回 projected ready StepRun ID,但不把读取结果解释为执行 claim。
|
||||
|
||||
当全部 required StepRun 终结时,纯契约给出固定的 Run terminal 建议:
|
||||
`failed/skipped → failed`,其次为 `timed_out`、`cancelled`,全部成功才为
|
||||
`succeeded`。terminal transition 同时绑定 expected Run version/event sequence、
|
||||
固定 error code、finished time 和不超过 36 字节的确定性 RunEvent identity;storage
|
||||
adapter 必须把它与本轮 StepRun mutation 原子提交。
|
||||
|
||||
### 4. 双方言使用同一 port,不新增 package
|
||||
|
||||
同一显式 subpath 公开最多 64 条的 keyset candidate page 和
|
||||
`listCandidates/advance` repository port:
|
||||
|
||||
- SQLite adapter 位于既有 `@qinglong/local-sqlite`,复用单
|
||||
`LocalSqliteOperationAuthority` 和 `BEGIN IMMEDIATE`;candidate SQL 只返回可推进
|
||||
pending dependency 或全部 StepRun 已终结但聚合 Run 未终结的 Workflow,不为 root
|
||||
ready 或等待中的 Workflow 制造空写;
|
||||
- PostgreSQL adapter 位于既有 `@qinglong/cluster-postgres`,由 caller 驱动有界
|
||||
keyset page;`advance` 使用短 `SERIALIZABLE` transaction,锁定聚合 Run 和完整
|
||||
StepRun 集合,使用数据库 transaction clock,并对 serialization/deadlock 做有界
|
||||
fresh-client retry;
|
||||
- 两者都先验证 immutable plan、Run identity 和所有 StepRun canonical JSON/mirror,
|
||||
再按 StepRun version/digest/status CAS;一轮只更新一次聚合 Run,version/event
|
||||
sequence 按 mutation 数加 terminal event 数整体推进;
|
||||
- StepRun、RunEvent、StepRunMutation 和 terminal Run/Event 同事务提交,任一 drift、
|
||||
fence 或写入冲突整体回滚;已终态 aggregate 重放只读收敛为 `settled`。
|
||||
|
||||
没有新增 migration、workspace package、第三方依赖、连接、timer、watcher 或后台
|
||||
scanner。ready Task 的执行 admission 仍必须在后续原子绑定 StepRun 与
|
||||
RunAttempt/Executor fence,frontier 的 ready projection 本身不是执行 claim。
|
||||
|
||||
### 5. admission replay 只冻结准入证据,不冻结当前执行状态
|
||||
|
||||
双方言 admission exact replay 继续严格验证 immutable plan、receipt、初始 RunEvent、
|
||||
初始 StepRun mutation 与 admission step ledger,但不再要求当前 Run/StepRun 永远停在
|
||||
准入初态。当前 aggregate 只允许合法运行/终态、identity 不变、canonical record
|
||||
完整且 version/event sequence 单调;初始 Event 查询固定截止 admission final sequence。
|
||||
因此合法 frontier/Executor 推进后仍可 inspect/exact replay,而历史准入证据缺失或漂移
|
||||
仍失败关闭。
|
||||
|
||||
## 不采用方案
|
||||
|
||||
### 把 Workflow 聚合 Run 交给普通 dispatcher
|
||||
|
||||
拒绝。聚合 Run 的 `taskId` 是 Workflow ID,revision 是 publication digest,不是一个
|
||||
普通 Task execution revision;直接分发会错误解释定义并把一个 DAG 当成一次 Task。
|
||||
|
||||
### 为恢复器伪造 RunAttempt 或把聚合 Run提前置为终态
|
||||
|
||||
拒绝。伪造 Attempt 会制造不存在的执行事实;提前终结会隐藏尚未执行的 ready/pending
|
||||
StepRun。
|
||||
|
||||
### 每 Workflow 常驻 coordinator
|
||||
|
||||
拒绝。它给低配路由器增加空闲内存、唤醒与写放大,并让 Cluster 正确性依赖进程内
|
||||
ownership。
|
||||
|
||||
### 新建 workflow package
|
||||
|
||||
拒绝。纯契约没有独立部署、重依赖或权限域,另拆会违反 D-207 的 package 粒度标准。
|
||||
|
||||
## 当前验证
|
||||
|
||||
1. 通用 PostgreSQL recovery SQL 影响评估为 LOW,新增 Workflow trigger exclusion;
|
||||
2. runtime-core 405/405,包含 frontier 纯契约 6/6 与后续 Attempt admission 4/4;
|
||||
3. `local-sqlite` 180/180;真实 SQLite frontier 覆盖 dependency ready、失败向下游
|
||||
skipped、成功/失败 aggregate terminal、bounded page、drift rollback、settled 与
|
||||
admission-after-progress exact replay;
|
||||
4. `cluster-postgres` 223 pass、1 条无测试 URL 条件 skip;mock 契约覆盖
|
||||
`SERIALIZABLE`、Run/StepRun row lock、单 aggregate CAS、terminal 原子写、
|
||||
40001 fresh-client retry、settled 与显式 subpath;
|
||||
5. PostgreSQL 18.4 arm64 physical HA 在禁止 image pull 下完整通过,包含
|
||||
`remote_apply`、timeline 1→2、旧主 fencing、promotion、`pg_rewind` 和两 fresh
|
||||
control replicas;新增
|
||||
`pluginPackageWorkflowFrontierTerminalizesAtomically`、
|
||||
`pluginPackageWorkflowFrontierExactlyReplays`、
|
||||
`pluginPackageWorkflowFrontierSurvivesPromotion` 三项 gate,总
|
||||
`passed=true`;
|
||||
6. HA durable facts 为 1 个 Workflow admission、5 个 Workflow RunEvent、3 个
|
||||
StepRunMutation;promotion 后 frontier 返回同一 `succeeded/settled` winner,
|
||||
admission 仍 exact replay;
|
||||
7. workspace 仍为 20 个 package,未新增生产依赖或常驻资源。
|
||||
|
||||
## 尚未关闭
|
||||
|
||||
1. ready Task StepRun 到 RunAttempt/Executor 的原子执行 admission;
|
||||
2. Workflow 取消、超时和 Task post-start recovery;
|
||||
3. frontier caller 与 Local application/Cluster control 生命周期装配;
|
||||
4. Edge/Standalone 真实断电、资源门和产品 API/CLI/UI。
|
||||
Reference in New Issue
Block a user