Files
Agent-System/.doc/remediation/2026-09-23-platform-deepening-reliability-ha-concurrency-plan.md
WeiCHEN 6b7c8495c5 docs(remediation): add platform deepening plan for decoupling, bus, reliability, HA, concurrency
Six-track plan (R1-R6) grounded in the 2026-09-23 four-way read-only
survey: server/chat/bizdev/workflow residual coupling, event bus ops
loop gaps (dead letters, serial dispatch, dual outbox), panic
recovery, single-host HA (replicas, PG hot standby, backup
automation), concurrency hotspots (docgov engine lock, sync long
tasks, pool tuning). Planned only; no code changes.
2026-09-23 11:19:33 +08:00

21 KiB
Raw Permalink Blame History

title, status, created, updated, owner, task_id, task_type, task_tier, policy_revision, branch, worktree, base_dev_sha, write_scope, allowed_environments, mutex, review_state, integration_state, deployment, cleanup, cleanup_owner, remote_sync
title status created updated owner task_id task_type task_tier policy_revision branch worktree base_dev_sha write_scope allowed_environments mutex review_state integration_state deployment cleanup cleanup_owner remote_sync
平台深度完善方案:解耦·通信·总线·可靠性·高可用·高并发 planned 2026-09-23 2026-09-23 Cursor platform-deepening-plan-2026-09-23 research multi_stage AGENTS+module-dev-standards+validation-contract @ 15fdb28a feature/platform-deepening-plan-2026-09-23 .worktrees/platform-deepening-plan-2026-09-23 15fdb28aa1
.doc
platform-deepening-plan pending pending not_required pending 独立维护者 not_requested

平台深度完善方案:解耦·通信·总线·可靠性·高可用·高并发

本文件是方案文档(planned),不含实施。六轨每批开工前另建 short-term 并在 CURRENT 认领。 上位约束不重写:模块化单体 ADR、模块开发规范、module-boundaries.yaml、架构设计、Phase 2 事件计划。 现状事实来自 2026-09-23 四路只读调研(事件总线 / 解耦边界 / 可靠性HA / 高并发,证据均为当日主仓 dev 实测)。

0. 用户目标与授权

  • 用户目标:在既有模块化单体基础上,继续深入研究并制定解耦、通信、总线、可靠性、高可用、高并发六个维度的深度完善方案。
  • 交付形态(用户已确认):研究+方案文档,不含代码实施;后续实施另立任务逐批落地。
  • HA 边界(用户已确认):单宿主机内深化——多副本容器、健康探针、本机流复制、备份自动化;不引入第二台机器、不新增外部消息中间件;跨机 HA 需先另立 ADR。
  • 红线继承(不变):不拆微服务、不引入进程内全局 bus 单例或跨包 RPC、FAV live 不放量、exceptions 不回涨、每批不改行为语义除非该批声明。

1. 现状基线(调研结论摘要)

1.1 已成立的能力(不推倒)

维度 已有 证据锚点
解耦 module-boundaries.yaml exceptions=0、baseline 全 0;9 个巨型文件已拆 ≤800 行;chat 不再 import app/*;docgov 枚举/哨兵进 vocabulary module-boundaries.yaml:492-502;residual 收口
通信 三种契约已运行:窄端口(消费者拥有)、PG 领域事件、wire DTO;组合根唯一(internal/app) 规范 §2;internal/app/app.go
总线 transactional outbox(UoW 同事务)、FOR UPDATE SKIP LOCKED claim、fencing token、per-(consumer,aggregate) 顺序(gap 规则)、幂等 inbox、off/shadow/live 三段切换、event_delivery_attempts 不可变审计 internal/events/{pg,dispatcher,worker}.go;goose 00035/00040-00043
可靠性 退避 1s→15min 封顶 12 次、dead/quarantine 状态、taskrun/chat 幂等键、文档编辑租约+fencing、崩溃恢复(crash-before-ack 测试) dispatcher.go:263-293;taskrun/store.go;docgov/lease.go
并发 agent 信号量 8、SSE 心跳+写期限续期、登录限流、会话 cap 4096、uow 序列化重试+lock_timeout agent/limiter.go;server/sse.go:47-55;app/uow/pg_uow.go

1.2 主要缺口(按维度,全部有代码证据)

解耦:server 适配层仍持 20+ 具体领域类型(server.go:43-77);chat↔coordinator 具体类型咬合(chat/session.go:53-56);bizdev 是「领域服务+二级组合根」双重身份(bizdev/service.go:70-198);workflow 四包网未单向化(批次 D 未做);archtest 事件正则盲区(scan.go:17 不匹配 taskrun.*/fav.*)。

总线:死信表零引用(无迁出/查看/重放入口);单 worker 进程内三 consumer 串行轮询(head-of-line 阻塞);纯 1s 轮询无唤醒;双 outbox 并存(遗留 outbox_events 插入即 published);correlation/causation 字段全空;replay 只有计划校验无执行器;handler panic 无 recover 会击穿 worker;指标仅进程内存原子计数。

可靠性:panic recovery 中间件缺失(全仓非测试 Go 无 recover());熔断器缺失;taskrun 终态事件可静默丢失(无 UoW 时 return nil);H6 stale-fencing 无限重放不计 Failed。

高可用:宿主机、各环境 PG、pi-agent runner、app 副本、events 实例全部单点;PG 无流复制/无 WAL 归档;备份纯手动无调度;升级即整组停机;docgov 内存缓存+进程内 mutex 隐含单写者进程假设。

高并发:docgov 单把引擎锁且锁内做 DB I/O(全进程文档读写排队);同步 /tasks/run 占 handler 75 分钟;taskrun 无 worker 池、run 数无界;SSE 无连接上限(每连接 2 goroutine);主 PG 池未调优(默认 max(4,NumCPU));LLM http.Client 每次新建不复用;agent 信号量 per-Backend 而非进程级;订阅者满即丢。

2. 目标架构(增量,不推翻)

flowchart TB
  subgraph edge [单宿主机内 HA 层]
    LB[前端入口 / nginx or docker LB] --> APP1[app 副本 1]
    LB --> APP2[app 副本 2]
  end
  APP1 --> PG[(PG 主)]
  APP2 --> PG
  subgraph workers [worker 层]
    EV1[events worker 1]
    EV2[events worker 2]
    TR[taskrun worker 池]
  end
  PG --> PGSB[(PG 流复制热备)]
  PG -. LISTEN/NOTIFY 唤醒 .-> EV1
  PG -. SKIP LOCKED .-> EV2
  subgraph domain [领域层(不变)]
    UOW[UnitOfWork + Outbox] --> OWN[表唯一写者]
  end
  APP1 --> UOW
  APP2 --> UOW
  EV1 --> INBOX[幂等 inbox] --> OWN
  EV2 --> INBOX
  OBS[metrics + 告警] -. scrape .- APP1

变化只在:edge(入口+多副本)、worker(多实例+池)、PG(热备+唤醒)、OBS(指标)。领域层、三种通信契约、表写者、事件信封 schema 全部不动。

3. 六轨分批计划

约定:每批独立 short-term + mutex + 验收 + 回滚;轨间按依赖排序但不互相阻塞关闭;合入 local dev 串行占集成槽位。

R1 解耦深化(结构轨)

批 内容 关键锚点 验收
R1-1 server 适配层收口:Server 具体字段逐域换用例端口;错误映射已收口到 domain_http.go 保持 server.go:43-77 archtest 新增规则「server 生产文件不得出现 *docgov./*bizdev./*coordinator. 字段类型」;现有路由特征测试状态码不变
R1-2 chat↔coordinator 解咬合:chat.Message/ChatResponse 去掉 coordinator.CoordinationResult/squad.AdvisorBriefing 嵌入,改 chat 自有视图类型;PendingAction.Kind 裸字符串两侧硬编码改 vocabulary 常量 chat/session.go:22-56;action_executor.go:58 ↔ coordinator/engine_docgov.go:242 生产 internal/chat 不 import coordinator/squad/docgov/taskrun;对话链 characterization 同绿
R1-3 bizdev 二级组合根上收:bizdev.NewService 内的装配(pool/迁移/docgov/docrevision/freedoc/projectworkflow/materialindex)搬回 internal/app;bizdev 回归纯领域服务 bizdev/service.go:70-198;bizdev/parts.go app 是唯一构造点;TestBizdevNoLocatorGetters 保持;启动链 characterization(health/schema)同绿
R1-4 workflow 网单向化(批次 D 残余):workflowdef→projectworkflow、workflow/runtime→projectinstance 改端口读定义 YAML L276-286 YAML imports 只删边不增边;工作流校验/门禁短测绿
R1-5 archtest 盲区修复:事件正则补 taskrun.*/fav.*;可选 block_kinds 声明恢复分层收紧;800 行门禁自动化(warn 起步) scan.go:17;YAML arch-check --mode block 绿;构造越权 taskrun 事件生产者的测试用例被拦截

依赖:R1-3 先于 R1-1(server 端口化需要 app 侧先有稳定构造面);R1-2 独立;R1-5 独立可先行(防回潮)。

R2 通信/总线深化(事件轨)

批 内容 关键锚点 验收
R2-1 worker 韧性:handler panic recover(fail 该 delivery 不崩进程);ErrStaleFencing 计入 Failed 并有限次后转 quarantine(关 H6) worker.go:199-283、:206-275 panic 注入测试:进程存活、delivery 走重试路径;stale-fencing 计数可见
R2-2 消费并行化:每 consumer 独立 goroutine + 批内有界并行(per-aggregate 互斥已由 claim SQL 保证);同 aggregate 串行语义不变 worker.go:106-152 1/2/4 worker×并行 handler PG race 测试;无重复可见副作用;head-of-line 消除的吞吐对比记录
R2-3 LISTEN/NOTIFY 唤醒:emit 事务提交后 pg_notify 新 channel,worker 监听唤醒轮询(保留 ticker 作兜底);背压:pending 超阈值时降 batch/提优先级 pg.go(InsertEnvelope 后);worker.go:107 空转 DB 查询量显著下降(对比记录);事件延迟 p99 ≤ 唤醒路径预期;积压告警可观测
R2-4 死信运营闭环:event_dead_letters 迁入/查看/重放 CLI(cmd/eventmode 扩展);dead/quarantine 告警出口 迁移 00035:40-45(表已建零引用);cmd/eventmode/main.go 死信可 list→inspect→replay(走既有 replay 双人审批);event_delivery_attempts 审计完整
R2-5 双 outbox 收敛:遗留 outbox_events 写路径(notification.EmitStageReadyToAdvance)迁到 envelope/delivery;reminder 轮询改事件驱动或保留但登记为有意轮询 notification/service.go:40-109;reminder.go:37-160 生产无 outbox_events 新写入;通知行为 characterization 同绿;旧表进入只读退役窗口
R2-6 因果链补全:三个生产者填 correlation_id/causation_id(docflow 从请求 ctx、taskrun 从 run id、intentflow 从 plan id);taskrun 无 UoW 时事件丢失改为显式补偿日志+metric(不允许静默 return nil) docflow/commands.go:275-282;taskrun/finalize.go:424-446 按事件 id 可还原 producer→attempt→receipt 全链;env 兜底硬编码 "dev" 移除(fail closed)
R2-7 表生命周期:event_delivery_attempts/event_reconciliations 归档任务(保留窗口与重放窗口对齐);envelope 按环境保留策略登记(不删数据,先立口径) inventory.go:14 归档任务 dry-run 清单+审批流;无未审批删除

依赖:R2-1 先行(后续并行化/唤醒的进程安全前提);R2-2 依赖 R2-1;R2-3 独立;R2-4/R2-6 独立;R2-5 独立但建议在 R2-4 后(复用 replay 入口)。

R3 可靠性深化(进程内轨)

批 内容 关键锚点 验收
R3-1 panic recovery 中间件:server 全路由 recover→typed 500 信封+request_id;taskrun runGuarded 已有,补 chat/sse 路径 server.go(Routes 链最外层) panic 注入测试返回固定信封,无连接挂死;access log 含 request_id
R3-2 LLM 网关韧性:进程级单例 http.Client+Transport 调优(MaxIdleConns/IdleConnTimeout)复用;runner 瞬态判定保持;可选轻量熔断(连续失败开窗拒新调用走模板降级) piagent.go:175;coordinator/dialogue_llm.go:96 连接复用可观测(单 client);熔断开/半开/闭状态机测试;模板降级链路已有保持
R3-3 TOCTOU/竞态收口:SaveWorkflowPlan upsert+revision 两事务合并单 UoW(关 C4);context.Background() 逃逸点改派生 ctx(关 H10 的高危子集) projectinstance;chat/session.go:178 并发 upsert 测试无中间态;审计清单列出剩余 Background 使用点与豁免理由
R3-4 迁移并发串行化:server/events 双进程启动都跑 goose——引入迁移锁(advisory lock 包裹 db.RunMigrations)或 events 不跑迁移只校验版本 bizdev/service.go:96;cmd/events/main.go:65 双进程同时冷启动 race 测试:迁移只执行一次,另一方等待/校验通过

R4 高可用深化(单宿主机轨)

红线内(多副本/探针/本机热备/备份自动化),跨机组件不出现。

批 内容 关键锚点 验收
R4-1 多副本前置去单点化(先决批,纯代码不改部署):docgov e.mu 锁内 DB I/O 消除(缓存改为锁外加载+版本失效);memDocs 缓存一致性方案(TTL 或事件失效,live 模式已切写路径);workspace LeaseTable 进程内 map 换 PG advisory/fencing docgov/engine_read.go:11-60;workspace/lease.go:5-35 1/2/4 app 实例并发正确性测试(规范 §10.2 基线);锁持有时间不再含 DB RTT(benchmark 记录)
R4-2 app 多副本 + 入口:compose deploy.replicas 或显式双服务;去掉固定 container_name;前端入口经单宿主机 LB(nginx 容器或 docker 网络内 DNS 轮询);session 从内存 map → PG 会话或粘性说明(会话 map 4096 上限是进程内的,多副本需 sticky 或无状态化评估) docker-compose.*.yml;server.go:420-442 滚动重启单副本期间 API 可用(探针门控);SSE 断线重连路径验证(after_seq 重放已有)
R4-3 PG 本机流复制热备:每环境加 standby 容器(primary_conninfo);WAL 归档到本地目录;promotion 手册(不自动 failover);RPO≈0(同步)/RTO 手动分钟级 docker-compose.*.yml system-db 段 备库 lag 指标可见;kill 主库→promote→应用重连演练记录(独立环境,不触共享)
R4-4 备份自动化 + SLA 文档:launchd/cron 调度 backup-system-db.sh;备份保留策略;RPO/RTO 目标写入 ops 文档;恢复演练周期化 scripts/backup-system-db.sh(已有);缺调度 定时备份产物+manifest 校验通过;演练报告;SLA 文档落地
R4-5 events 多实例:compose 起 2 个 events worker(SKIP LOCKED+fencing 已支持);owner 唯一化 docker-compose.dev.yml:153-180;cmd/events/main.go:68 双 worker 无双 lease/无重复可见副作用(复用 E0B 验收模式)
R4-6 pi-agent 韧性:评估 runner 多实例(并发闸在 app 侧 per-Backend 的缺陷先由 R5-3 进程级信号量修复)+ healthcheck 驱动 restart 已有;单实例降级路径(模板)已有,登记为接受项或升双实例 deploy/pi-agent/ 决策记录(ADR 级短文):接受单实例+降级 或 双实例方案

依赖:R4-1 必须先于 R4-2(多副本正确性前提);R4-5 独立;R4-3/R4-4 独立;R4-6 依赖 R5-3 结论。

R5 高并发深化(吞吐轨)

批 内容 关键锚点 验收
R5-1 docgov 锁重构:单 e.mu 拆分(读路径 RWMutex/按文档 id 分锁);读路径去锁内 DB;这是 R4-1 的并发视角同一批(合并实施) docgov/engine.go:15-20;engine_read.go 并发文档操作 benchmark(同文档热点/跨文档并行分开压测,规范 §10.2);p95 改善记录
R5-2 同步长任务异步化:POST /tasks/run 同步模式改「提交即返回 run_id + SSE/轮询订阅」(异步范式已存在 sse.go:358);保留同步模式但加排队上限;75 分钟写期限绕过退役 handlers_chat_task.go:183-230;sse.go:57-62 前端迁移(web 轨);并发 N 任务时 handler goroutine/连接占用对比记录
R5-3 进程级 agent 信号量:agent.NewBackend 每调用新建带独立信号量的实例改为共享进程级 semaphore(或 backend 单例化);上限可配 squad/service.go:259;agent/limiter.go 多 squad 并发时总 LLM 并发 ≤ 全局上限测试;MAX_CONCURRENT_AGENTS 语义升级为进程级
R5-4 SSE 与连接治理:SSE 总量上限(超限 503 typed 信封);订阅 channel 满即丢→有界阻塞+丢弃计数 metric+客户端降级提示;chat/tasks 端点限流(对齐登录限流模式) sse.go;taskrun/manager.go:560-570,633 上限触发返回 typed error;丢弃计数可观测;限流负例测试
R5-5 池与客户端调优:主池显式 MaxConns/MinConns/MaxConnLifetime/HealthCheckPeriod(env 可配,与 DB max_connections 对齐预算);LLM client 复用(与 R3-2 合并实施) bizdev/service.go:82 池配置生效可观测;压测下无连接耗尽(ErrConnBusy 为零)
R5-6 taskrun worker 池(可选):run 启动从无界 goroutine 改有界池+队列深度 metric;与 R5-3 信号量配合决定是否必要 taskrun/manager.go:327-337 队列深度/饱和度 metric;风暴注入测试排队而非放大

依赖:R5-1=R4-1 同批;R5-2 前端迁移另立 web 批次;R5-5 独立可先行(低风险高收益);R5-3 独立;R5-6 依赖 R5-3 后评估。

R6 可观测性深化(观测轨)

批 内容 关键锚点 验收
R6-1 app /metrics:沿用 events JSON 计数器模式先落(HTTP 中间件计数:qps/时延/状态码/panic;docgov 锁等待;池饱和)——不引 Prometheus 依赖(红线:不新增外部组件;JSON 与 events 现状一致) cmd/events/main.go:116-124 为范式 /api/v1/metrics(或同端口)可用;重启清零已知并登记
R6-2 事件积压与死信告警:queue age/oldest pending/dead/quarantine 周期采集(worker 内已有 backlog 查询)+ 告警出口(日志级即可,对接现有 slog) events/worker.go Metrics;ListBacklog 积压超阈值日志告警可见;与 R2-3/2-4 联动
R6-3 链路追踪轻量版:request_id→correlation_id 已有字段,补「对话/任务全链 id 透传」核验用例(不引 OTel) httpx/envelope.go:76-88 e2e 断言:一次任务从 HTTP 到事件 receipt 全程 id 可检索

4. 依赖与波次总览

flowchart LR
  R15[R1-5 archtest 盲区] --> R11[R1-1 server 收口]
  R13[R1-3 bizdev 上收] --> R11
  R11 --> R12[R1-2 chat 解咬合]
  R14[R1-4 workflow 单向]
  R21[R2-1 worker 韧性] --> R22[R2-2 并行消费]
  R21 --> R23[R2-3 NOTIFY 唤醒]
  R24[R2-4 死信闭环] --> R25[R2-5 双 outbox 收敛]
  R26[R2-6 因果链]
  R31[R3-1 panic 中间件] 
  R32[R3-2 client 复用+熔断] 
  R33[R3-3 竞态收口]
  R34[R3-4 迁移锁]
  R41[R4-1/R5-1 docgov 锁] --> R42[R4-2 app 多副本]
  R43[R4-3 PG 热备]
  R44[R4-4 备份自动化]
  R45[R4-5 events 双实例]
  R53[R5-3 进程级信号量] --> R42
  R53 --> R46[R4-6 pi-agent 决策]
  R52[R5-2 长任务异步化]
  R54[R5-4 SSE 治理]
  R55[R5-5 池调优] --> R42
  R55[R5-5 池调优] --> R32
  R61[R6-1 app metrics] 
  R62[R6-2 积压告警] 
  R63[R6-3 链路核验]

波次建议(可并行、合入串行):

  • W1 快赢低风险:R2-1、R3-1、R3-4、R5-5、R6-1、R1-5
  • W2 吞吐与韧性:R2-2、R2-3、R3-2、R5-3、R5-4、R6-2
  • W3 结构收口:R1-3、R1-1、R1-2、R1-4、R2-4、R2-6
  • W4 HA 演进:R4-1/R5-1、R4-2、R4-5、R4-3、R4-4
  • W5 长尾:R5-2(含前端)、R2-5、R2-7、R3-3、R5-6、R4-6、R6-3

5. 全局验收门(每批公共)

  1. ./scripts/arch-check.sh --mode block + go vet + 受影响包 go test -short(代码批)或文档验证契约(文档批)。
  2. 涉事件契约的批:TestRegistryParityWithYAML 必须在跑到的包内通过。
  3. 涉并发的批:PG race 测试 + 1/2/4 实例正确性(规范 §10.2),p50/p95/p99 与锁等待记录进 test report。
  4. 涉多副本/热备的批:kill/promote/滚动重启演练记录;不触共享环境(dev 独立环境内)。
  5. 红线核查单:无新增 exceptions、无新跨模块 import、无新外部中间件依赖、FAV 保持 off、MULTI_INTENT_PLAN_TIER 不动。

6. 风险与回退

风险 控制
R4-2 多副本引入缓存/会话一致性 bug R4-1 先行 + 1/2/4 实例正确性门;不合入则单副本回退(部署层改动,revert compose 即回)
R2-3 NOTIFY 在 PG 池/代理下不可靠 保留 ticker 兜底;NOTIFY 只作延迟优化不作正确性依赖
R2-2 并行消费破坏 per-aggregate 顺序 顺序由 claim SQL(同聚合互斥+gap 规则)保证,与并发度正交;race 测试固化
R1-3 bizdev 上收装配面大 characterization 锁启动链行为;分两步(先构造搬移、后 Parts 收窄)
R5-2 前端迁移长尾 同步模式保留+排队上限兜底;前端批次独立 mutex
事件表无限增长(R2-7 拖延) 归档先立口径(本方案)不删数据;监控 queue age 提前预警

每批独立 revert;迁移全部 additive;部署层改动(compose)与代码改动分提交。

7. 与既有文档的关系

  • 本方案 = Phase 2 计划(Track E/S/P)之后的下一层平台深化:Track E 已交付总线骨架,本方案补运维闭环/吞吐/HA;Track S 残余并入 R1;HTTP/PI 协议仍归各自 remediation。
  • 批次 A–G(2026-09-20 分批计划)中未完成项映射:批次 A→R1-1、批次 B 深层→R1-2、批次 D→R1-4;巨型文件/例外清零已落地不重复。
  • gap-matrix/FEATURE-MATRIX 不因本方案变更(planned 状态不产生发布门禁变化);各批落地时按实际升行。

8. 开工准入(第一批前)

  1. 每批建 short-term(YYYY-MM-DD-<slug>.md)+ CURRENT 认领 + mutex 登记。
  2. 从当时 dev tip 建任务 worktree;policy_revision 重读。
  3. 涉共享环境(R4-3/R4-4 演练)须 env:dev 能力单独授权。
  4. 本方案文档状态保持 planned;首批实施时在 INDEX 与本文件登记映射,不代填验收。