Files
next-tjwater-server/docs/workbench-database-rollout.md
T
jiang 1d061f6099
Generic Container CI/CD / test-build-publish (push) Failing after 6s
Server CI/CD v2 / build-test-publish-and-deploy (push) Failing after 6s
feat: add project-scoped operations
2026-10-22 18:40:20 +08:00

10 KiB
Raw Blame History

工作台数据库变更门禁

本规则适用于工作台、工况任务、Agent Run、事件日志、通知、预约工单和告警在项目 BizDB 中的 DDL、数据回填、种子写入与清理操作。MetaDB、TimescaleDB 和外围系统数据库不在本文范围内。

当前基线

2026-10-21 凤阳结构扩展

维护者明确要求将 tjwater_v2 的表结构和业务配置复制到 fengyang_v2,同时保留凤阳现有管网及数据。本次单独扩展凤阳,不向其他项目批量写入。以下旧迁移状态为当时记录,以本节的实际核对结果为准。

新增 workbench 的告警事件、告警状态、任务访问申请、任务进度、Agent 消息共 5 张表,补齐 peripheral_sample 的 8 张空表、source_gis 的 4 张空表及通用 gis.water_quality_monitoring_points 视图。同步主项目的约束、索引与业务表列注释,事件主题约束支持调查进度和展示事件。时序库的应用表结构已经一致,本次未迁移或写入时序数据。

本次迁移已完成,一次性执行脚本已清理。当时先生成差异报告,再做全库备份、核对 pg_restore --list、在强制回滚事务中演练,最后单事务应用。固定源、目标物理库为 tjwater_v2 和 fengyang_v2。生成的迁移 SQL、备份及审计报告保留供追溯;后续结构变更仍按本文门禁单独核对范围。

本次备份与审计记录位于忽略目录 data/project-rollout/fengyang_v2-20261021T041825Z/,包含 before.dump、backup.list、migration.sql 和 report.json。备份摘要:f0f68f689239e3fde7fda10b6e7a0cbfdf4f8ee625ab87d3f714162af9391f87。不提交备份或生成数据。

回滚演练及应用时均逐表核对已有 network、asset、gis 基础表的行数和无序内容摘要。凤阳的 31,143 个节点、31,219 条连接、50 个 SCADA 设备保持原状;未复制奉贤模型、原始 GIS、演示工单、历史结果、项目成员或地图范围。复查差异报告中缺失对象、约束差异和索引差异均为空。

外围 API 现按已验证项目的 Metadata DB 路由选库,不再固定为 tjwater_v2。事件生产事务排序锁在当前连接的项目库内生效,不创建数据库对象或业务数据;外围工单仅在该项目已配置事件表时发布事务事件。后台进程支持显式 OPERATIONAL_WORKER_PROJECT_IDS 列表,既有部署配置和服务身份成员权限未自动扩展。前端使用选中项目路由;上线后仍需按实际身份完成 Server/Agent 的跨项目联调验收。

已从当前前端配置的 GeoServer 核对两个工作空间的 WFS 数据。凤阳返回 31,137 个 junction、30,016 条 pipe,其余节点和连接类型仍使用凤阳原模型;这些分类数量与模型总节点/连接数量不是同一指标。

若结构迁移失败,事务直接回滚。若提交后的恢复需要使用 before.dump,先停止该项目写入并按既有数据库恢复流程处理,不能在仍有新业务写入时直接覆盖恢复。

截至 2026-09-24,014_operational_tasks.sql 和 015_workbench_events_and_task_runs.sql 已应用到 tjwater_v2、szh_v2、md_v2、fengyang_v2 和 zjb。这是已有基线,不代表后续迁移可以继续批量应用。

017_workbench_schema_comments.sql 只为 workbench schema 及其 17 张表和关键列增加数据库可见注释。它先在 tjwater_v2 应用;其他项目数据库保持原状,直到 tjwater_v2 验证通过并获得明确扩展确认。

019_operational_task_access_requests.sql 已只在 tjwater_v2 应用,新增带表级和列级注释的任务访问申请表;初始记录数为 0。旧 workbench.work_orders 已退役,因此应用后 workbench schema 仍为 17 张表,而不是继续增加重复投影。其他项目数据库尚未应用 019。

未应用 019 的项目仍可读取既有工况任务,但创建访问申请会明确返回 503 DEPENDENCY_UNAVAILABLE,不会以缺表异常形成 500。单个任务同一时间只允许一个待审核访问申请;需要先审批或拒绝当前申请,避免 Agent 用不同请求号重复放大通知和事件。

018_remove_synthetic_check_task_projections.sql 清理曾被错误同步为预约任务的通用合成检查投影。它按完整 peripheral_sample:<work_order_id> 标识关联外围源,只匹配 general 类型、没有调查动作回执关联且由专用 seed actor 创建的旧检查任务;不使用用户可编辑的标题或工单状态作为删除依据。投诉与爆管事件以及调查产生的现场采样工单均不在清理范围。同步器使用同一专用 seed actor 阻止旧种子检查再次生成。

旧的三条演示工单已迁入 peripheral_sample.work_orders,并同步为有效的 external_work_order 任务。021_retire_workbench_work_orders.sql 仅在物理数据库为 tjwater_v2、旧表恰有这三条且每条都有有效外围工单和任务投影时删除旧表。其他四个项目数据库原本没有旧表,不执行本迁移。旧种子和迁入脚本已退役,不能再运行历史 011 重建双份数据。

后续数据库变更默认只写入 tjwater_v2。其他项目保持现状,必须等 tjwater_v2 验证通过并由维护者明确确认后,再逐库扩展。禁止把“所有活跃项目”作为写操作的默认范围。

通知生命周期迁移 022_operational_notification_lifecycle.sql 只修改现有通知 JSON 文档与列注释,不新增表或物理列。脚本带物理数据库名硬门禁;先在 tjwater_v2 核对待审批通知仍为 active、已审批通知变为 resolved,并验证 Header 统计所有当前用户有权处理的活动事项。已读只表示用户看过,不能隐藏尚未解决的事项。未取得维护者确认前,不向其他 BizDB 应用。

变更顺序

  1. 核对目标 DSN,确认物理数据库名为 tjwater_v2,并确认没有其他项目共享该 BizDB。
  2. 对目标库做完整、可恢复的备份。备份需通过 pg_restore --list 或等价方式检查,路径和校验值记录在部署记录中,不提交到仓库。
  3. 在强制回滚事务或由备份恢复出的临时库中执行完整迁移。只做静态 SQL 检查不能替代这一步。
  4. 只在 tjwater_v2 提交迁移,提交后立即核对表、列、约束、索引、回填数量和项目 ID。
  5. 完成接口、工作进程和浏览器验收。未通过时停止扩展,保留备份和现场信息。
  6. 维护者确认验收结果后,按一个项目一次的方式扩展。每个项目重新执行备份、回滚演练和验收,不复用 tjwater_v2 的通过结论。

SQL 文件包含自己的 BEGIN 和 COMMIT 时,不能在外层简单包一层 ROLLBACK 充当演练。演练工具需要移除脚本自己的事务边界,或在由备份恢复出的临时数据库中运行。

验收条件

tjwater_v2 同时满足以下条件后,才可以讨论扩展:

  • 迁移重复执行不会产生重复记录或改变已经确认的终态数据。
  • 表、约束和索引与迁移定义一致,没有其他项目 ID 的记录。
  • 带 Bearer 和 X-Project-Id 的 sync-snapshot 返回 200,游标、任务和通知可以解析。
  • SSE 可以连接、发送 keepalive,并能从持久游标补读事件。
  • 至少一条合成调查完成 queued、running、waiting_human 的主路径,计划、报告和通知属于同一执行代次。
  • Agent 或 Server 重启后,旧 Run 和旧会话不能覆盖当前代次。
  • Server、Agent 和前端的相关自动化测试通过,联调期间没有新增 5xx、跨项目数据或重复事件。

没有定义固定观察时长。验收记录至少包含执行时间、代码提交、迁移编号、备份标识、自动化测试结果和真实接口结果,由维护者决定是否扩大范围。

维护脚本也受范围限制

会枚举 Metadata DB 中所有活跃路由并写入数据库的脚本,属于跨项目变更。此类脚本必须提供显式项目参数,并默认拒绝全项目写入。

cleanup_workbench_events.py 会枚举所有活跃项目,但已经支持 --project-id。dry-run 可以查看全部项目;写入模式必须显式传入经核对属于 tjwater_v2 的项目 UUID,禁止省略 --project-id。种子、导入、回填和修复脚本同样不能把所有活跃项目作为隐式目标。

当前设计需要收敛的部分

现有设计保留以下主干:

  • operational_tasks 保存业务任务,operational_task_runs 保存每一代 Agent 执行。两者生命周期不同,分表有助于租约恢复和阻止旧代次写回。
  • domain_event_log 保存可重放事件,LISTEN/NOTIFY 只负责唤醒。当前规模不需要增加 Redis、Kafka 或新的中继服务。
  • 通知表表达用户收件箱,事件日志表达状态变化。两者不能合并。
  • 证据、计划、报告和动作修订需要保留历史版本,独立表符合审计和并发更新要求。

以下部分不再扩展:

  • operational_tasks 仍保存执行代次、执行请求号、Agent session 和租约字段,同时 Run 表也保存同类数据。新代码以 Run 表为准,不再增加任务表上的执行字段。待 tjwater_v2 稳定后,再设计前向迁移移除兼容字段。
  • status、lifecycle_status 和任务 JSON 中的状态存在重复表达。新接口以 lifecycle_status 为业务生命周期,以 Run 状态为执行状态,不再增加第四套状态字段。
  • 定时任务表和 schedule API 不在当前产品主路径。相关结构保留兼容,不继续增加调度能力,除非 tjwater_v2 出现明确业务需求。
  • JSON 文档与标量列只保留查询、约束或兼容所需的重复字段。新增字段应先确定唯一权威来源,不能同时在多处独立计算。

新增表需要同时满足三个条件:对象有独立生命周期,访问或保留策略与现有表不同,并且 tjwater_v2 的真实用例证明复用现有结构会造成明显问题。否则优先收敛现有模型。

失败与回滚

2026-10-08 的 事件链路收敛 没有 DDL 或持久数据迁移。新增事务排序保护按实际连接的物理数据库名仅启用 tjwater_v2;并发及源事件验证使用强制回滚事务。其他数据库未被写入或迁移,扩展仍需明确确认。

任何数据库出现迁移失败、接口 5xx、跨项目记录、Run 代次错乱或游标异常时,立即停止后续项目。未提交的事务直接回滚;已经提交且不能安全前向修复时,按该项目的迁移前备份恢复。不要为保持各项目版本一致而继续扩大故障范围。