10 KiB
Dispatcher 任务状态、控制与临时数据迭代计划 v0.1
状态:项目内 v0.4 Schema、隔离 Mock、代码及本地验收已完成,证据见 dispatcher-v04-local-acceptance.md;外部 SaaS/management 未签收、未联调。 历史项目内 v0.3 见 thirds/v0.3.md,上一轮计划见 plan-config-read-v0.1.md;已发布外部合同不因本地切换改变。下一版目标合同见 thirds/v0.4.md。本计划不授权真实拨号、ECS、生产切换或清理任何现存数据。
1. 问题与完成定义
- 历史 v0.3 的重启从 SQLite 持久事件游标续读;项目内 v0.4 已改为每次重启取得完整任务归属清单,游标仅在该次进程内用于在线增量发现。发现页不再代替独立的 MQ 控制队列切换任务状态。
- 历史
pause/stop可选择drain;项目内 v0.4 已改为两者均挂断该任务的在途通话并核验终态,resume不挂断。两类 MQ 命令均不因消息年龄失效;历史积压控制与外呼、新鲜拨号授权及未来issued_at外呼的边界需通过失败测试与回归证明。 - Dispatcher SQLite 持有接纳/幂等、未知通话占用、执行快照、录音/最终结果与 outbox;v0.4 仅增加已终止任务配置副本的显式条件清理,不自动删除现存数据。SaaS 尚无可验证的全部执行事实和应用收讫,不能把这些 SQLite 记录当作可无条件删除的缓存;不以日志代替事务和恢复事实。单节点 SQLite 不要求高可用,不因此允许已接纳的未知呼叫重拨。
- 历史控制处理为定位一个任务读取全部任务归属;v0.4 已按 D+task ID 直接索引查询,600 条历史任务的查询计划测试未扫描全表。
**完成标准:**项目内下一版严格合同/Schema/正反例/来源与哈希、Mock SaaS 故障矩阵先通过;再基于 TDD 替换运行路径且不保留已废弃模式。验证重启全量、在线增量、控制顺序/挂断、停止排空、历史积压外呼的新鲜授权、未来 issued_at、任务结束清理及数据库故障;至少执行本模块格式检查、go vet ./...、go test -race ./...、构建,业务模块覆盖率 ≥65%。不能将计划或 Mock 当作已交付功能/真实 SaaS 验收。
2. 必须先冻结的合同边界
| 项目 | 下一版目标 | 冻结前不得声称已解决的问题 |
|---|---|---|
| SaaS→D 入站队列 | 两类仍保留:每 D 一条独立控制队列 task.control,每归属任务一条任务队列 call.execute;均由 SaaS 创建/退役,D 只消费。结果另走 D→SaaS 队列。 |
不将任务列表轮询替代控制队列,不将控制队列误当任务队列。 |
| 重启全量 | 每次进程重启从 SaaS 读取本 D 的完整、一致、有界分页任务清单(含队列未退役的 stopped 任务),在全部页核验、应用前关闭新执行;不以本地旧游标跳过全量。 | 冻结全量分页标识/边界、水位、完整性、遗漏任务与 removed 的含义;未拿到完整清单不得从已有队列拨号。与现行 v0.3 after=0 事件回放不同,不能重解释旧游标。 |
| 在线增量 | 内存游标仅在运行期使用,发现新增/撤销/归属变化;状态切换由独立 MQ 控制队列实时处理。重启重新全量,无需为发现长期保留旧事件/无限墓碑。 | 冻结增量页丢失、无序/中断、连续性及全量重取规则;变更页 incidental status 不可自动解除暂停/停止,也不能成为第二个状态命令。身份或状态冲突须关闭准入并报错。 |
| 全量与控制交接 | 在重启清单核验和控制积压处理期间关闭新执行;按任务串行处理有效控制及接纳。SaaS 先持久状态再发控制;不得先开任务消费后才处理已积压控制。 | 冻结快照水位与已发布/积压控制顺序、历史积压、重复/迟到控制逐条处理的证明;MQ 命令不因时间积压过期。队列暂时为空不是 SaaS 不再发布的保证;不凭消息到达先后把旧 pause 当作最新 resume。 |
| 控制副作用 | pause/stop 关闭准入并对该任务所有在途通话发挂断,失败保持关闭并可追踪;resume 不挂断。stop 仍静默 ACK 未接纳积压,停止回执只在排空条件达成后应用。 |
删除 drain 作为 pause/stop 有效选项前,冻结 Agent 实际终结确认、超时/重试边界、错误回执以及已接纳通话的唯一最终结果。不能把 Agent 收到指令等同于通话已结束。 |
| 控制积压 | 不合并为“每个任务只执行最后一条”:pause 挂断后 resume、stop 不可逆和逐条控制回执有中间副作用。 | 只有另行变更为纯状态设置、移除中间副作用及原回执合同,才能重新讨论合并;本轮不做。 |
| SaaS 证据与清理 | SaaS 是业务配置与最终结果的目标来源;D 仅保存执行中所需最少的本地事务/恢复事实。 | 当前 RabbitMQ publisher confirm 不是 SaaS 应用收讫;必须先决定 SaaS 应用回执/可查询恢复事实及最长重投期限,才能冻结何时安全删除本地执行身份、已发布 outbox 和防重记录。未确认时保留并报告阻塞。 |
| 日志 | 文件系统诊断日志记录原值任务/通话/消息 ID、号码、时间、状态、错误、挂断与清理阶段;日志只用于排查。 | 用户要求“所有内容原样记录”与现行禁止密钥、私钥、完整音频/对话入日志的约束冲突,不纳入实施目标;该冲突未获解除前不得写入这些内容,也不得用日志代替可靠状态。 |
不为全量/增量自行猜测新 JSON 字段、SaaS 应用回执或保留期限;这些须作为 F01/F07 合同、严格 Schema、正反例与 Mock 的同一版本冻结。新合同不原地改写 contracts/upstream/v1/ 或已运行的 docs/contracts/task-discovery-v0.3-proposal.schema.json,也不复活 v0.2 的旧 changes/410 字段来冒充新版本。
3. 实施顺序(项目内完成;外部签收仍未完成)
- 合同与迁移门禁。 与 SaaS 明确全量分页/增量连续性、归属撤销、单任务只读配置继续存在、控制队列积压及任务队列退役、SaaS 最终结果应用收讫或可恢复查询范围;发布项目内新版本 Schema、拓扑/正反例、来源/hash 与 Mock C。历史项目内 v0.3 与已发布外部 MQ v0.1 不能冒充 v0.4;已发布 upstream/v1 未修改。
- 先写失败用例再切发现。 重启不使用旧发现游标直接作为续读起点,先读一致全量,全部页面核验后才能接任务队列;在线增量只增删归属,不从状态字段擅自恢复暂停;失败/分页断裂关准入,控制队列照常消费。迁移时排空/确认旧任务、旧未确认占用和 outbox,不能直接删旧 SQLite 或并跑新旧发现。
- 控制路径。 保留独立 D 控制队列和逐条回执;暂停/停止首先关闭新执行、退回未接纳交付,及时对该任务所有在途通话挂断,终结事实另外确认;停止仍须排空未接纳队列后回 stopped/applied。历史 stop 即使积压很久仍须按序挂断、排空并回逐条结果,不能只停 consumer 留队列。两类 SaaS→D MQ 命令无
not_after到期语义;历史外呼在接纳与拨号前仍按当前任务、白名单、时段、独立授权、额度及通话时限校验,失败拒绝且不自动重拨。未来issued_at的call.execute拒绝提前接纳。 - 临时 SQLite 收敛。 盘点每张当前表的写入/引用和所有外键,区分在途状态、未知占用、未交付结果、SaaS 已核收事实及有界防重记录;仅对满足全部安全条件的已完成任务批量清理。先保证幂等身份与可恢复结果不会因删除而重拨/丢失,再清配置副本/历史终结事实。清理阶段留日志、计数、耗时及失败原因;失败显式阻断或重试清理,不影响仍需恢复的记录。具体保留期和 SQLite/WAL 空间回收频率以容量测试和 SaaS 回执合同为依据,不猜定值。
- 性能与文档。 控制按 D+task ID 直查;在大量历史任务下验证单次控制查询不随全部历史线性增长。同步更新项目入口、任务发现/控制合同、代码发布版本与部署/测试证据;旧文档加历史标识但保留可追溯证据。
4. 本地验收场景
- 重启多页完整清单、分页期间新增/移除、崩溃后再次从全量恢复;运行期增量断页和旧游标故障不跳项、不误撤销;旧状态资料不能覆盖新消费状态。SaaS 停止发布前任务队列不能由 D 删除;独立控制队列即使发现不可用也能处理控制。
- 在途两通分别收到 pause、stop 后均挂断;resume 不挂断;Agent 挂断失败、响应成功但终态未知、控制回执丢失均不误报完成、不重拨。pause→resume、pause→stop、stop→resume、重复/历史积压控制按实际副作用与终态验收,不只检查最后状态。
- stop 未接纳积压静默 ACK、已接纳通话各发唯一最终结果;SaaS 停止发布/队列排空/回执/退役的顺序可追溯。历史 stop/断线重启不遗留永不排空的队列;未来 issued_at 的外呼绝不提前发出。
- 任务完成但 outbox 未确认、SaaS 尚未核收、上传中、未知呼叫、重复命令晚到和 SQLite 写失败时不误清;仅显式清理已证实安全的任务配置副本,历史任务查询使用索引;数据库整体大小/长期保留期仍依赖未签收的 SaaS 收讫与重投期限,不能宣称有界;原值诊断字段可追查,日志无实际凭据、完整音频/对话。
**外部阻断项:**真实 SaaS 尚未签收全量/水位和控制交接合同、没有可验证的 SaaS 应用收讫/恢复事实与重投期限,因此本轮仅完成项目内 v0.4 实现和隔离 Mock,不得宣称 SQLite 可随时清空或生产可用。现行单节点/单 Cell/单租户、禁止真实拨号和不自动提交/清理工作树的边界不变。