mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
152 lines
11 KiB
Markdown
152 lines
11 KiB
Markdown
# ADR-0122:单 Cadence Worker Session 产品生命周期
|
||
|
||
- 状态:Proposed(exact wire、共享 client、Session coordinator、capacity oracle、product/process composition、credential material provider 与单身份部署基线已实现;远端 credential recovery、真实 Cluster 全链、Linux/固定设备证据仍是发布 Gate)
|
||
- 日期:2026-07-23
|
||
- 关联 RFC:QL-RFC-0001 D-05、D-06、D-14、D-85、D-108、D-120、D-121
|
||
- 关联 ADR:ADR-0012、ADR-0057–ADR-0061、ADR-0108、ADR-0110、ADR-0112、ADR-0121、ADR-0123、ADR-0234
|
||
|
||
## 背景
|
||
|
||
本 ADR 提出时,Cluster Control 已在独立 mTLS/`ql3w` ingress 上提供 Worker Session 的
|
||
`register|heartbeat|transition` 路由,PostgreSQL repository 也已拥有 generation/version/lease
|
||
fencing,但 route 仍直接解析手写 JSON,Worker Runtime 也没有 Session client。当前增量已用共享
|
||
runtime contract 和 Worker product composition 收敛这两处缺口;后续 Gate 仍不得回退到第二套协议。
|
||
|
||
旧 `back/runtime/application/workerHeartbeatLifecycle.ts` 只用于早期单控制面孵化:它依赖 legacy
|
||
Worker domain,自建 heartbeat timer,并由另一个 `HeadlessWorkerRuntime` 拼接 execution drainer。
|
||
ADR-0121 已建立单 journal owner、单 mTLS Agent 和单 Profile cadence 的 production execution plane。
|
||
直接复用旧 lifecycle 会重新产生两套 Session shape、两个 timer、两个 client ownership,并可能在
|
||
Session offline 或 Agent close 后仍留下需要 completion/lease supervision 的本地进程。
|
||
|
||
## 决策
|
||
|
||
### 1. Session wire 必须 exact、versioned 且 path-bound
|
||
|
||
在现有 `@qinglong/runtime-core` 增加一个懒加载 Session transport subpath,不新增 package。三个
|
||
request/response schema 固定为:
|
||
|
||
- `qinglong/worker-session-register@v1`;
|
||
- `qinglong/worker-session-heartbeat@v1`;
|
||
- `qinglong/worker-session-transition@v1`。
|
||
|
||
Worker/Session identity 只来自既有 path;body 不重复 principal,也不携带 credential。register request
|
||
最多 20 KiB,以容纳 16 KiB canonical capability snapshot;heartbeat/transition request 与所有 response
|
||
最多 4 KiB。未知字段、未知 schema、非 canonical capability、generation/version/status/lease 漂移均
|
||
fail closed。register 的 replacement fact 只在 response 中表达,HTTP status 保持统一且可重放的 200。
|
||
|
||
Cluster ingress 必须调用 contract parser/serializer,不再维护第二套 ad-hoc key list。现有认证和耐久
|
||
audit 仍先于 body;PostgreSQL repository 仍是 generation、version 和数据库时钟的唯一 authority。
|
||
|
||
### 2. Session 与 execution 必须共享一个 HTTPS client/Agent
|
||
|
||
Session adapter 留在 `@qinglong/worker-runtime`,并消费 ADR-0121 的同一个
|
||
`WorkerIngressHttpsClient`。不得为 register/heartbeat/transition 创建第二个 Agent、第二套 credential
|
||
provider 或独立 socket budget。client path allowlist 扩展必须精确到三个 Session operation,不放宽
|
||
Artifact stream 或通用 URL。
|
||
|
||
credential provider 仍在每个请求前惰性加载 certificate、private key、trust 与 `ql3w` token;本 ADR
|
||
不允许把这些材料复制进 Session journal。ADR-0123 已实现 active certificate + 原子 token 文件的具体
|
||
读取/轮换消费与 Buffer dispose;Session transport 已把 401/403/409 分为 credential rejected/session fenced,
|
||
使 Pull 立即暂停并允许同一 Session 在 token 修复后 heartbeat 恢复。远端 credential issue/revoke/recovery、
|
||
delivery acknowledgement 和管理面失败编排仍是后续 Gate,缺失时 product bootstrap 保持默认关闭。
|
||
|
||
### 3. Session coordinator 不拥有 timer
|
||
|
||
新增 caller-driven Session coordinator,只拥有以下显式操作:
|
||
|
||
1. `register()`:生成新 UUIDv7 Session,提交 canonical capability 与初始 capacity;
|
||
2. `tick(now)`:仅在到达 heartbeat due time 时提交一次 heartbeat,禁止重叠;
|
||
3. `beginDrain()`:持久化 `draining + availableSlots=0`;
|
||
4. `disconnect()`:只在 execution plane 已证明 settled 后持久化 `offline`。
|
||
|
||
它不得调用 `setTimeout/setInterval`。ADR-0121 的唯一 Profile cadence 同时驱动 Session due check 和
|
||
execution tick;Edge/Node 可使用不同 cadence,但 heartbeat 频率独立受 5 秒–5 分钟硬边界约束。临时
|
||
transport failure 只能在现有 lease 内由后续 cadence 重试;fence、credential rejection 或本地已观察
|
||
lease expiry 必须立即停止 Pull,不能自动用新 Session 接管旧 Session 下仍活动的 execution。
|
||
|
||
### 4. Capacity 必须来自单一 execution oracle
|
||
|
||
部署不得注入与 journal 无关的任意 available-slots 数字。production composition 必须从同一 owner
|
||
journal、当前 in-flight Pull reservation 与最大并发预算派生 `availableSlots`,范围始终为
|
||
`0..maxConcurrentRuns`。startup reconciliation 未完成、recovery required、draining 或 Session
|
||
unavailable 时必须为 0。
|
||
|
||
能力快照使用 runtime-core 的 canonical Remote Worker capabilities;capability JSON/hash、Profile、
|
||
架构、Runtime 和 Executor 不能由 HTTP response 临时改写。Edge 默认并发与 page 更小,Node 可提高
|
||
有界预算;两者都不增加 per-Run timer 或 socket。
|
||
|
||
### 5. 启停顺序由一个 product composition root 拥有
|
||
|
||
启动顺序固定为:
|
||
|
||
1. disabled/Profile/config gate,且 disabled 在读取路径和 credential 前返回;
|
||
2. 创建单 credential provider 与单 HTTPS client;
|
||
3. 取得 journal owner并完成全部有界 startup reconciliation;
|
||
4. 只有无 recovery fact 才注册 Session,并发布由 execution oracle 计算的 capacity;
|
||
5. 启动唯一 `unref` Profile cadence,之后才允许 Pull。
|
||
|
||
关闭顺序固定为:
|
||
|
||
1. execution `beginDrain()` 先 Abort Pull,但保留 journal owner与 shared Agent;
|
||
2. Session `beginDrain()` 在控制面耐久写入 0 capacity;
|
||
3. 唯一 cadence 继续 heartbeat 与 completion-first supervision;
|
||
4. 所有 inbox record settled 后才 transition `offline`;
|
||
5. 最后释放 journal owner、关闭 transport 与 shared Agent。
|
||
|
||
drain timeout、Session fence、heartbeat lease expiry、offline 失败或 recovery fact 都不得强制 close。
|
||
进程仍有可能产生 completion 时,不能为了满足 shutdown 时限丢弃唯一 owner。等待 shutdown proof 的
|
||
timer 必须保持 ref;只有常驻 cadence unref。
|
||
|
||
## 被否决的替代方案
|
||
|
||
1. **直接复用 `back/**` heartbeat lifecycle**:引入 legacy domain、第二 timer 和第二 shutdown owner。
|
||
2. **Session 与 execution 各建一个 HTTPS client**:重复证书、Agent、socket 与 credential rotation 状态。
|
||
3. **每 500 ms 都发 heartbeat**:Node cadence 会把副本和路由设备的空闲成本放大。
|
||
4. **先 register available 再做 startup recovery**:控制面会把未证明安全的 Worker 当成可调度候选。
|
||
5. **drain timeout 后 offline/释放 owner**:把预算耗尽伪装成副作用已经停止。
|
||
6. **允许部署直接上报 availableSlots**:容量与本地 durable execution authority 可漂移。
|
||
7. **为 Session lifecycle 新建 workspace package**:没有独立部署、依赖或权限责任,违反 D-85。
|
||
|
||
## 验收 Gate
|
||
|
||
1. runtime exact contract 覆盖三个 schema、byte cap、unknown field、authority drift 与 canonical capability。
|
||
2. Cluster ingress 继续证明 auth/audit-before-body,并以 PostgreSQL 16 最小权限角色验证完整 fence/replay。
|
||
3. Worker 真实 TLS 1.3 测试在同一 Agent 连续执行 register、heartbeat、Offer、completion 与 transition。
|
||
4. startup recovery 前零 register;recovery required 时零 Session/零 Pull。
|
||
5. 单 cadence、heartbeat due coalescing、in-flight 不重叠和本地 lease expiry fail closed 有确定性测试。
|
||
6. shutdown 证明 drain capacity 0 → execution settled → offline → owner/Agent release;所有失败路径保留 authority。
|
||
7. Edge/Node 固定设备资源证据证明没有新增 package、数据库、per-Run timer 或第二常驻 socket。
|
||
|
||
## 当前实现证据
|
||
|
||
1. `@qinglong/runtime-core/worker-session-transport` 已提供三个 exact v1 schema、20 KiB/4 KiB
|
||
request cap、4 KiB response cap、canonical capability 与 authority drift 校验;Cluster ingress 已复用
|
||
parser/serializer,并继续在 body 前完成认证与耐久 audit。
|
||
2. `@qinglong/worker-runtime/session-transport` 和 `/session-lifecycle` 已在同一
|
||
`WorkerIngressHttpsClient` 上实现 register/heartbeat/transition;coordinator 无 timer、请求串行、按 due
|
||
heartbeat,并在本地 lease expiry 后停止暴露可执行 Session。
|
||
3. `WorkerExecutionCapacityOracle` 只读取 owner journal 与 durable pending claim;reconciling、draining、
|
||
recovery 和 offline 一律发布 0,不接受部署直接注入 slots。
|
||
4. `@qinglong/worker-runtime/product` 在 startup reconciliation 后注册 Session,复用 execution 的唯一
|
||
cadence;真实 TLS 1.3 测试证明 register → draining → offline 共用一个 socket/Agent,且历史未结算
|
||
journal 在零 register 时失败关闭。
|
||
5. 确定性顺序测试证明 Session tick 与 execution tick 不重叠,shutdown 按 execution drain → Session
|
||
drain → heartbeat/supervision → offline → owner/transport release 收敛,并覆盖 offline 后 owner release 首次
|
||
失败的幂等重试。当前 Worker 129/129;D-218 本切片未改动共享 contract 或 Cluster
|
||
ingress,后者继续由 D-216/D-217 的完整回归与 PostgreSQL HA 门覆盖。
|
||
6. ADR-0234 已增加 `ql3-worker` production binary、disabled-before-secret process config、
|
||
direct-file identity bootstrap、持久 certificate store、信号先行和 incomplete-drain 持续持权;
|
||
独立 Worker 镜像闭包为 3 个 workspace package/24 个 runtime external,Kubernetes 固定
|
||
单身份单副本、Recreate、PVC 和 projected authority 私有物化。产品入口仍必须由明确
|
||
Worker Profile 配置激活,不能由其他部署默认开启。
|
||
7. macOS arm64/Node 24.18 真实进程+mTLS资源门测得 edge active/peak
|
||
`67,616,768/71,090,176` bytes、node `67,911,680/71,286,784` bytes,均为一个
|
||
TLS 1.3 socket并完成 register/drain/offline;64 MiB 被明确否决,edge 暂按至少
|
||
96 MiB 规划。尚未完成 Gate:真实 Cluster ingress/PostgreSQL 全链、
|
||
credential issue/revoke/recovery、Linux image/cgroup 与固定设备断网/休眠/断电证据。
|
||
因此本 ADR 与 D-121 仍保持 Proposed。
|
||
8. 历史 23 package dependency/source audit 为 `findings=[]`,Edge import audit 为 `compatible=true`;六种本机
|
||
制品均通过 pack/offline install/import,最大 standalone-application 为 2,474,124 bytes、411 files、
|
||
72 loaded modules,且制品闭包不包含 `@qinglong/worker-runtime`。runtime-core 新 contract 使本机制品比
|
||
D-120 快照增加两个文件,作为“不新增细碎 package”的显式可见成本保留。
|