2026-06-01 · DECISION TRACE

Hindsight 0.7.1 Postgres 升级风险与方案 C 规划

保留方案、指标、验证、复盘和治理判断,让结论能够追溯。

2026-06-01记录日期
决策记录记录类型
17章节数

Hindsight 0.7.1 Postgres 升级风险与方案 C 规划

  • HTML: https://decision.ht1072.top/2026-06-01-hindsight-071-postgres-migration-risk.html
  • Local HTML: [已移除本地路径]
  • Generated: 2026-06-01T18:32:45+08:00

Hindsight 0.7.1 Postgres 升级风险与处理规划

页面摘要区

结论: Hindsight 0.7.x 的方向是对的,它解决了 memory_linksentity 类型边 O(N²) 膨胀的问题;但当前 v0.7.1 官方包在本机 0.6.2 → 0.7.1 Postgres 升级路径上存在 migration 硬阻塞,不建议直接升级 live。

核心风险: 官方 migration 中多处 DROP/CREATE INDEX CONCURRENTLY 会在 Alembic/SQLAlchemy 事务块内执行,Postgres 报错 cannot run inside a transaction block;同时 hindsight-api-slim 依赖里只有 psycopg2-binary,实际迁移路径还需要 psycopg

推荐策略: 暂不动 live 0.6.2;先向上游提交 issue;如果要推进方案 C,应做 patched 0.7.1 + cloned DB rehearsal + clone-and-swap cutover,而不是 in-place 直接升。

行动清单: 1)保留本次审计目录;2)发布本决策记录到 wiki/HTML;3)向 vectorize-io/hindsight 提 issue;4)等待官方修复或准备可审计 production patch;5)fresh dump 重跑 rehearsal 后再讨论生产维护窗口。

风险边界: rehearsal 中为了验证 runtime,曾在 isolated venv + copied DB 中把 CONCURRENTLY 改成普通 DDL,这不能直接作为 production 方案;生产要么使用真正的 Alembic autocommit,要么拆出手工 pre-migration / batch cleanup。


1. 背景

本机当前 live Hindsight:

API: 127.0.0.1:8889
Version: 0.6.2
Status: healthy
Database: pg0/PostgreSQL 18.1 on 127.0.0.1:5432

本次任务是评估上游 0.7.1 是否值得升级,以及是否能安全从本机 live 0.6.2 迁移过去。

隔离演练路径:

isolated venv: [已移除本地路径]
isolated API: 127.0.0.1:18889
rehearsal DB: hindsight_071_rehearsal_20260601_151948
审计目录: [已移除本地路径]

live 8889 和 live DB 未直接修改。


2. 0.7.x 解决的问题

上游 issue #1887 指出,0.6.xmemory_linkslink_type = 'entity' 行会按高频实体近似 O(N²) 增长,导致表膨胀、dead tuples、stats 慢查询、CPU 飙高和连接池耗尽。

官方在该 issue 中说明,0.7.0 已重新设计:

  • entity edges 不再物化为 memory_links 行;
  • entity relationships 改为从 unit_entities 按需派生;
  • migration e9b2c7d1f3a4_drop_entity_memory_links 会删除既有 entity links。

本机 rehearsal DB 迁移前后验证:

迁移前 memory_links:
semantic | 53180
entity   | 39372
temporal | 38768
caused_by| 981

迁移后 memory_links:
semantic | 53200
temporal | 38788
caused_by| 981

说明 0.7.x 的方向和目标是有效的。


3. 本机实测阻塞点

3.1 缺少 psycopg

hindsight-api-slim 0.7.1 安装后包含:

psycopg2-binary==2.9.12

但启动 migration 时 SQLAlchemy 使用 postgresql+psycopg 路径,报:

ModuleNotFoundError: No module named 'psycopg'

补救方式:

uv pip install --python [已移除本地路径] 'psycopg[binary]'

3.2 CONCURRENTLY 在 transaction block 中执行

psycopg 后,migration 继续失败:

DROP INDEX CONCURRENTLY cannot run inside a transaction block

已撞到的 revision:

e1b2c3d4f5a6_drop_unused_indexes.py
e9b2c7d1f3a4_drop_entity_memory_links.py

继续扫描上游 v0.7.1/main 发现同类写法还存在于多个 migration:

a2b3c4d5e6f8_add_gin_index_source_memory_ids.py
b3c4d5e6f7g8_add_temporal_date_indexes.py
c1a2b3d4e5f6_enable_pg_trgm_and_entities_trgm_index.py
d2e3f4a5b6c7_add_memory_links_expansion_indexes.py
d4e5f6g7h8i9_gin_source_memory_ids_fastupdate_off.py
e1b2c3d4f5a6_drop_unused_indexes.py
e9b2c7d1f3a4_drop_entity_memory_links.py

上游 mainv0.7.1 的相关 migration 文件对比结果为 SAME,说明截至本次检查时,上游 main 尚未修复该问题。


4. 隔离验证结果

为了验证 0.7.1 runtime 本身是否可用,本次只在 isolated venv + copied rehearsal DB 中做 rehearsal-only patch:

将 CONCURRENTLY 改成普通 DDL
移除 migration 中手写 COMMIT

这不是 production 方案,只用于确认 runtime 能力。

补丁后 isolated 0.7.1 启动成功:

{"status":"healthy","database":"connected"}
{"api_version":"0.7.1"}

验证通过:

banks ✅
stats ✅
manual retain ✅
manual recall ✅
consolidation ✅
operations clean ✅

关键结果:

alembic_version: b5a4c3e2f1d8
pending_operations: 0
failed_operations: 0
pending_consolidation: 0
failed_consolidation: 0

5. 对 live 的影响

短期:本机 live 仍健康,当前 rehearsal DB 规模较小,不是马上要抢修。

DB size: 104 MB
memory_links: 39 MB
entity links: 39372

中长期:继续停留在 0.6.2 会保留 entity links 膨胀风险。如果后续 retain、历史回放、consolidation 增加,memory_links 表可能持续膨胀。

直接升级的风险更高:如果直接在 live DB 上跑官方 0.7.1 migration,可能出现 API 启动失败、alembic_version 半路状态、索引部分删除、DB schema 中间态等问题,回滚不能只退 Python 包,可能需要恢复 dump。


6. 方案 C:patched 0.7.1 的规划

6.1 原则

不做 in-place 硬升。采用:

patched 0.7.1 + cloned DB rehearsal + clone-and-swap cutover

6.2 Patch 范围

只修 migration/依赖,不改业务逻辑。

  1. 补依赖:
psycopg[binary]>=3.3.0
  1. CONCURRENTLY migration:

将:

op.execute("COMMIT")
op.execute("DROP INDEX CONCURRENTLY IF EXISTS ...")

改为:

with op.get_context().autocommit_block():
    op.execute("DROP INDEX CONCURRENTLY IF EXISTS ...")
  1. 单独处理 e9b2c7d1f3a4 的 entity cleanup。

生产更稳的方式是将大规模 entity links 删除拆成可观测 batch cleanup:

DELETE FROM memory_links
WHERE ctid IN (
  SELECT ctid
  FROM memory_links
  WHERE link_type = 'entity'
  LIMIT 50000
);

循环直到 0 行,并在结束后:

VACUUM ANALYZE memory_links;

6.3 Rehearsal 要求

fresh dump 新建 rehearsal DB,必须验证:

health/version/banks/stats
manual retain/manual recall
consolidation operation completed
alembic_version == head
entity links cleared
pending_operations = 0
failed_operations = 0

还要记录:

migration 耗时
entity cleanup 耗时
DB size 前后变化
memory_links dead tuples / vacuum 后状态
索引列表

6.4 Cutover 策略

生产采用 clone-and-swap:

  1. 维护窗口开始,停止 Hindsight API 写入;
  2. final dump live DB;
  3. 恢复到新 DB,如 hindsight_071_prod_candidate_<timestamp>
  4. patched 0.7.1 指向 candidate DB 跑 migration;
  5. isolated API 验证通过;
  6. systemd/env 切换到 patched venv + candidate DB;
  7. live 8889 验证通过;
  8. 保留旧 0.6.2 venv、旧 DB、旧 env 和 final dump 作为回滚点。

6.5 回滚

不依赖 downgrade migration,直接切回旧 venv + 旧 DB:

stop hindsight-api
restore env/systemd to 0.6.2 + old DB
start hindsight-api
verify health/version/stats/recall

7. 建议

当前建议:

不直接升级 live。
先向上游提交 issue。
等待官方修复,或准备可审计 production patch 后 fresh rehearsal。

如果后续继续推进方案 C,应先把 patch 做成可重复脚本/本地分支,并至少完成两次 fresh rehearsal,再安排生产维护窗口。


8. 证据与路径

本机审计目录:

[已移除本地路径]

关键文件:

verify-banks.json
verify-retain.json
verify-recall-after.json
verify-consolidate-operation.json
verify-stats-final.json
*.noconcurrent.diff
hindsight-071-api-18889-*.log
venv-freeze-hindsight-ish.txt
uv-install-psycopg.txt

上游相关:

Repo: https://github.com/vectorize-io/hindsight
Issue #1887: Entity links grow O(N²) per shared entity...
Issue #1902: PostgreSQL upgrade to v0.7.1 fails: missing psycopg and CONCURRENTLY migrations run inside transaction blocks
Release: v0.7.1, 2026-05-28

本次已提交的上游 issue:

https://github.com/vectorize-io/hindsight/issues/1902

9. 当前执行状态

本记录生成时间:2026-06-01 18:31:18 CST。

本记录用于 wiki / HTML / Hindsight retain pointer 归档,并作为向上游提 issue 的依据。