Files
go-sip/docs/plan-0926.md
T

50 lines
8.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 任务发现统一事件游标分页计划(设计稿 v0.1)
> 状态:**历史 v0.3 设计依据**;下文“当前”均指当时的 v0.3 实现,不是现行项目内运行版本。现行 Dispatcher 项目内 v0.4 已完成本地实现与隔离验收,见 [`新计划`](plan-dispatcher-state-v0.1.md)、[`v0.4 合同`](thirds/v0.4.md)及[验收证据](evidence/dispatcher-v04-local-acceptance.md);真实 SaaS/management 仍未签收、未联调,也未部署或拨号。[v0.2](thirds/v0.2.md) 与本文件 v0.3 仅保留历史;未改写已发布外部合同。
## 1. 目标和不变边界
当前 v0.2 首次返回全量 `tasks`,之后返回独立的 `changes`,还需处理过期游标与 410。目标是**只保留一种任务列表形状**:首次按页读取,后续沿同一事件游标读取更新;不再提供 `changes`、`operation` 或两套响应模式。`after` 是变更事件序号,**不是任务 ID,也不是按任务 ID 排序的翻页位置**。任务 `a01` 更新后可以在下一页或下一次查询中再次出现。
| 已确认方向 | 约束 |
| --- | --- |
| 统一 `tasks[]` | 新任务按 `task_id` 识别;已有任务只因 `status` 变化触发任务生命周期动作。其他已有字段仍用于身份、归属和一致性校验,不因其变化擅自重置运行中执行。 |
| 事件游标分页 | 首次查询和每约 30 秒的后续查询都允许多页;每页有界,Dispatcher 以返回的游标继续,直到本轮无更多任务。SaaS 不必一次返回该 D 的全部任务。 |
| 撤销 | 在同一 `tasks[]` 中以 `status=removed` 返回墓碑项;没有任务出现在某一页**不等于**撤销。撤销不删执行恢复、幂等或 outbox。 |
| 永不过期 | 不提供 `cursor_expired`/410 自动重建路径;SaaS 必须保证旧游标仍可继续看到尚未消费的任务变化及撤销。游标无效、记录丢失或无法证明连续时拒绝新执行并报错,不静默重置。 |
| 控制与队列 | MQ 的 pause/resume/stop 即时控制不等 30 秒轮询;SaaS 独占创建、绑定和退役任务队列,Dispatcher 只消费预建队列。 |
本轮仅实现并验证单 Dispatcher、单 Agent、单 Cell、单租户的本地 Mock 路径;单 D 当前任务上限 256 不因分页放宽。其他 SaaS 项目内协议维持 v0.1;不修改 `contracts/upstream/v1/`,不授权真实供应商、云资源、拨号或切换。
## 2. 项目内 v0.3 读取语义(外部未签收)
- 路径沿用 `/internal/v1/dispatcher/tasks`;使用现有受控 D 身份。首次从起始事件序号读取(项目草案记为 `after=0`),以后发送**上次已持久化**的 `next_cursor`。`next_cursor` 代表本页最后一个已返回任务的事件位置,不能跳到尚未返回的全局最新事件。
- 每次 HTTP 200 都使用 `tasks[]` 和 `next_cursor`,不再区分 `snapshot`、`changes`。`tasks[]` 可以为空;空页表示本轮追平,游标不跳跃。非空页的游标必须前进。项目内 v0.3 已冻结为规范十进制游标、单页最多 256 项、仅响应级 `next_cursor`,不增加 `has_more` 或逐项 `event_id`;必须读到空页,不能凭“本页少于上限”推断结束。
- SaaS 对该 D 的任务按**各自最新变更事件序号**升序分页;该序号必须持久、单调且不可复用。同一任务在两次查询之间多次更新,只需返回足以表达**最新状态**的记录,不要求保存每次中间状态。若分页期间再次更新,新的序号必须使该任务可再次被读到;绝不能因游标前进跳过尚未返回的任务。
- 普通任务沿用已确认的身份、原值 `tenant_key`、归属和状态字段。`removed` 墓碑必须至少能唯一定位原 D、租户和任务;其余必填规则由项目内 v0.3 Schema 定义;`task_revision` 是任务状态修订,不能代替事件序号,也不从旧 `changes[].operation=removed` 猜字段。已存在任务的租户/任务归属与本地绑定冲突时拒绝处理,不静默迁移。
- Dispatcher 对新 `task_id` 建立归属并核验 SaaS 预建队列;对已有任务按最新 `status` 更新 SaaS 状态并应用更严格的准入约束。发现页中的 `paused→running`(即使事件较新)只更新状态和游标,不解除已持久的暂停;须收到 MQ `resume`、重新读取单任务并确认 `running`,才恢复原队列。`stopped` 不可逆;`removed` 阻止新接纳,已有在途执行、最终结果和 outbox 按原身份收口,不由轮询触发重复拨号或擅自强挂。`status` 不变时可推进游标,但不重复执行控制动作。任务配置仍通过单独的只读任务接口核验,不让发现列表替代执行快照。
`tasks[]`、`next_cursor` 的项目内精确字段与正反例已按 [`v0.3 Schema`](contracts/task-discovery-v0.3-proposal.schema.json) 冻结并在 Mock 验证;**不是 SaaS 现网或对外正式合同**。逐项不带 `event_id`,Dispatcher 不能独立证明 SaaS 页内排序/没有漏项;完整有序返回、长期墓碑及授权绑定仍需 SaaS/业务另行签收。
## 3. 持久化、启动和失败边界
1. 新加入或重启的 D 先从本地已提交游标继续;没有新协议游标时从起始序号逐页读取。完成首次追平、核验队列和配置前,不消费执行队列或开放新拨号;MQ 控制仍可处理。每页校验 D 身份、任务数上限、身份绑定、状态和游标连续性。
2. **任务记录与本页游标必须在同一 SQLite 事务提交**。进程在提交前崩溃则重读原页;提交后重读只会按同一任务身份幂等应用。启动是否已经追平须单独持久标记,不能因为读到第一页就认为拥有完整任务清单。
3. 请求失败、响应不完整、页大小超限、非空页游标不前进、重复/倒退位置、身份冲突或 SQLite 提交失败时,不推进游标,不用部分列表推断缺席任务已撤销,拒绝新执行并保留现场错误日志。成功追平并重新完成当前准入核验后才可恢复;不等下一窗口自动拨号、不换线、不重拨。
4. 当前 v0.2 游标**不能**直接解释为新事件游标。切换前需有独立版本与受控排空/恢复核验;无法证明旧任务、积压及在途执行安全收口时停止切换,不清除旧执行事实或重建执行身份。不得同时运行 v0.2 与新任务发现消费者,也不提供新接口失败后回退旧增量路径。
## 4. “永不过期”的实际成本和阻断项
SaaS 可以维护每个任务的最新事件序号及状态,而不必为 `changes` 另建完整的逐次变更响应。但 D 可能长期离线且仍持有任意旧游标,因此**已撤销任务的墓碑和足以恢复顺序的序号不能提前丢弃**。删除墓碑、复用序号或无声截断历史都与“永不过期”冲突。活跃任务上限 256 **不限制历次撤销的累计数量**;墓碑存储量和首次分页追赶耗时会持续增长。
在 SaaS/业务签收容量预算、长期保留责任、备份恢复后事件序号不回退、旧 D 游标的可读性和极端积压上限之前,**不能把该方向称为可上线或有界容量方案**。若这些条件无法满足,必须另行确认恢复/清理合同,而不是在实现中偷偷设置过期、忽略墓碑或返回伪造的空页。
## 5. 本地结果与后续外部门禁
1. **F07 合同**:发布与当前 v0.2 并列区分的新项目内任务发现版本;冻结起始游标、排序/翻页结束、单页和总量边界、墓碑身份、状态及错误响应;提供正反例、哈希和严格 Schema。旧 v0.2 合同仅保留历史,不原地改写成已发布合同。SaaS/业务签收与项目内 Mock 通过分别标注。
2. **F03 实现**:在独立分支以先失败的测试驱动替换配置读取、逐页应用、SQLite 游标和启动追平门禁;移除旧 `changes`/410 运行路径,不保留双模式或故障回退。更新发布制品的合同版本与摘要核对,保持其他 v0.1 业务接口不变。
3. **F09 本地验收**:覆盖首轮多页、空页、同任务再次出现且状态变化、墓碑、分页并发更新、跨重启重读、控制与轮询竞态、SQLite 写失败、异常游标及错误页;证明不误删、不重拨、不绕过 SaaS 队列所有权。按本轮 P1 业务模块的覆盖率口径验证,Mock 结果不冒称真实 SaaS 或生产验收。
4. **F06 切换阻断**:只有新合同、容量责任、版本化制品、旧状态排空及实际 SaaS 联调各自签收后,才讨论真实部署;本文不授权真实外呼、OSS、ECS、供应商消费或生产切换。
项目内完成记录:F07 v0.3 Schema/正反例/哈希与 Mock C,F03 v0.3 按页持久化及失败拒新,F09 单节点/单租户本地矩阵见 [`f09-local-acceptance-v0.3.md`](evidence/f09-local-acceptance-v0.3.md);F06 本地发布阻断见 [`f06-local-release-gates-v0.3.md`](evidence/f06-local-release-gates-v0.3.md)。不把这四项本地完成记录外推为 SaaS 顺序、墓碑容量或真实部署签收。