ea6e56b304
发布通道原来只有三条:PostgreSQL 关系行、Elasticsearch 分片、OSS 对象。 WeKnora 的 wiki 图谱是 wiki_pages 一张纯 PG 表(in_links/out_links 存 slug), 所以它不在任何通道里——撤权后生产 wiki 会一直留着已撤权文档的页面与引用。 本次新增第 5 条通道:库级 wiki 快照,挂在现有文档发布包里,检索与 wiki 同一个 release 单元(同一次执行、同一次校验、同一次回滚): - 导出:ExportWiki 按 knowledge_base_id 全量读 wiki_pages/wiki_folders; 收敛门禁(库内无解析中/合成中文档)不满足直接失败并给中文原因; 未启用 wiki 且无 wiki 行的库不参与同步(生产 wiki 保持原样)。 - 撤权:item.Action == "delete" 时在导出端剥离该文档的 wiki 贡献 (source_refs/chunk_refs 去条目、无引用页面整页不带、摘死链、清 parent_slug、 无页面引用的空文件夹及其祖先一并去掉),使“源端仍在只停止发布”和 “源端删除”两种情况收敛到同一结果。 - 导入:库级 replace-by-kb(同一事务内 DELETE by kb 后灌入快照,文件夹先于页面), 新增 ReplaceWiki 供撤权路径使用(文档行只 disable,wiki 整体替换)。 - 校验:VerifyWiki 用生产 WeKnora wiki API 比对页面 slug 集合,撤权时额外断言 生产 wiki 不再引用被撤权文档。 驱动与验收:新增 cmd/release-channel-e2e(复用发布 worker 真实代码路径, 支持 publish/withdraw/rollback),scripts/wiki_e2e_test5.sh、 scripts/wiki_e2e_newkb.sh 两套端到端脚本;证据见 docs/WIKI_CO_TRANSPORT_ACCEPTANCE.md。
107 lines
6.5 KiB
Bash
107 lines
6.5 KiB
Bash
#!/usr/bin/env bash
|
||
# wiki 同搬通道 5 文档验收脚本(本地模拟生产 = 测试服 weknora-test-v071)
|
||
# 用法:bash scripts/wiki_e2e_test5.sh
|
||
# 前置:三条 ssh 隧道(172.17.0.1:25432/29200/28080)已起,dist/release-channel-e2e 已构建
|
||
set -uo pipefail
|
||
cd "$(dirname "$0")/.."
|
||
REPO=$PWD
|
||
KB=c12ff4d5-dd87-423b-ab0f-af745b9d54a7
|
||
WK=http://127.0.0.1:8080
|
||
CFG=/run/release-sim/release.sim.json
|
||
DIST=$REPO/dist/release-channel-e2e
|
||
|
||
api() { curl -s -K /tmp/wk_curl.cfg "$@"; }
|
||
prod_sql() { docker run --rm --network host --env-file /tmp/target_pg.env postgres:16-alpine psql -At -P pager=off -c "$1"; }
|
||
prod_es_count() { # 用 keyword 子字段精确匹配(knowledge_id 是 text 字段,UUID 会被分词)
|
||
curl -s "http://172.17.0.1:29200/weknora_test_chunks/_count" -H 'Content-Type: application/json' \
|
||
-d "{\"query\":{\"bool\":{\"filter\":[{\"term\":{\"knowledge_id.keyword\":\"$1\"}},{\"term\":{\"is_enabled\":true}}]}}}" \
|
||
| python3 -c "import sys,json;print(json.load(sys.stdin).get('count'))"
|
||
}
|
||
release() { # release <knowledge> <mode> <revision>
|
||
docker run --rm --user "$(id -u):$(id -g)" \
|
||
--network knowledge-governance-p1_default --network weknora071full-network \
|
||
--add-host prod-pg:host-gateway --add-host prod-es:host-gateway --add-host prod-weknora:host-gateway \
|
||
-v "$REPO/secrets/release-sim":/run/release-secrets:ro \
|
||
-v "$REPO/config/release.sim.json":/run/release-sim/release.sim.json:ro \
|
||
-v knowledge-governance-release-bundles:/var/lib/knowledge-governance/release-bundles \
|
||
-v "$DIST":/release-channel-e2e:ro \
|
||
--entrypoint /release-channel-e2e knowledge-governance-p1-release-worker:latest \
|
||
-config "$CFG" -knowledge "$1" -mode "$2" -revision "$3" 2>&1 | grep -E "STEP|bundle|wiki (before|after)|route kb"
|
||
}
|
||
|
||
echo "### 1. 上传 4 篇同主题文档(与首篇共贡 wiki 页)"
|
||
write_doc() { cat > "/tmp/wiki_e2e_$1.md"; }
|
||
write_doc b <<'EOF'
|
||
# 来源与目录:停止知识的语义
|
||
|
||
知识治理平台在“来源与目录”视图里可以停止某条知识。停止的含义是:生产端不再检索它。
|
||
需要注意,停止不会改动测试端 WeKnora 的 wiki:只有删除文档才会触发 wiki 清理链。
|
||
因此 wiki 快照在撤权时由发布通道负责剥离该文档的贡献。
|
||
EOF
|
||
write_doc c <<'EOF'
|
||
# 发布通道之 PostgreSQL 与 Elasticsearch
|
||
|
||
发布通道把知识治理平台评审通过的知识写进生产端 WeKnora。
|
||
PostgreSQL 负责关系行:knowledges、chunks、knowledge_tags、resources。
|
||
Elasticsearch 负责检索分片与向量,索引名称为 weknora_test_chunks。
|
||
撤权时 Elasticsearch 通过 delete-by-query 清空该文档分片。
|
||
EOF
|
||
write_doc d <<'EOF'
|
||
# 发布通道之 OSS 对象与图片资源
|
||
|
||
文档里的图片与附件存放在对象存储 OSS。发布时先写入暂存路径,再用 CopyObject 拷到生产桶。
|
||
resources 表保存 storage:// 定位符,搬运时只替换桶名。
|
||
知识治理平台与测试端 WeKnora、生产端 WeKnora 共用同一套对象通道实现。
|
||
EOF
|
||
write_doc e <<'EOF'
|
||
# 撤权与回滚演练
|
||
|
||
撤权(withdraw)会把生产端知识置为 disabled 并清空检索分片,同时重放 wiki 快照。
|
||
回滚(rollback)会整包还原上一版 revision,包括 wiki 快照。
|
||
因此生产端 WeKnora 永远不会出现“检索没了、wiki 还在”的中间态。
|
||
EOF
|
||
for k in b c d e; do
|
||
id=$(api -X POST -F "file=@/tmp/wiki_e2e_$k.md" -F "fileName=wiki-e2e-$k.md" "$WK/api/v1/knowledge-bases/$KB/knowledge/file" | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['id'])")
|
||
echo "doc $k -> $id"
|
||
printf '%s\n' "$id" > "/tmp/wiki_e2e_id_$k"
|
||
done
|
||
|
||
echo "### 2. 等 5 篇全部收敛(parse=completed 且 wiki 子任务为 0)"
|
||
for i in $(seq 1 40); do
|
||
pending=$(docker exec WKNFull-postgres psql -U weknora -d weknora_full -At -c "select count(*) from knowledges where knowledge_base_id='$KB' and deleted_at is null and (parse_status <> 'completed' or pending_subtasks_count > 0)")
|
||
total=$(docker exec WKNFull-postgres psql -U weknora -d weknora_full -At -c "select count(*) from knowledges where knowledge_base_id='$KB' and deleted_at is null")
|
||
pages=$(docker exec WKNFull-postgres psql -U weknora -d weknora_full -At -c "select count(*) from wiki_pages where knowledge_base_id='$KB' and deleted_at is null")
|
||
echo " [$i] docs=$total 未收敛=$pending wiki_pages=$pages"
|
||
[ "$total" -ge 5 ] && [ "$pending" = "0" ] && break
|
||
sleep 20
|
||
done
|
||
|
||
echo "### 3. 逐篇发布(每次发布会推整库 wiki 快照)"
|
||
i=0
|
||
for id in $(cat /tmp/wiki_e2e_id_b) 9be3e0fa-e699-4a8e-be0c-0d934ee33294 $(cat /tmp/wiki_e2e_id_c) $(cat /tmp/wiki_e2e_id_d) $(cat /tmp/wiki_e2e_id_e); do
|
||
i=$((i+1))
|
||
echo "--- publish #$i $id"
|
||
release "$id" publish "wiki-e2e-5doc-p$i" | tail -4
|
||
done
|
||
|
||
echo "### 4. 生产端证据(5 篇)"
|
||
prod_sql "select 'enabled='||count(*) filter (where enable_status='enabled')||' total='||count(*) from knowledges where knowledge_base_id='$KB'"
|
||
prod_sql "select 'wiki_pages='||(select count(*) from wiki_pages where knowledge_base_id='$KB')||' wiki_folders='||(select count(*) from wiki_folders where knowledge_base_id='$KB')"
|
||
echo "共贡页面(source_refs 多于一条):"
|
||
prod_sql "select slug||' <- '||source_refs::text from wiki_pages where knowledge_base_id='$KB' and jsonb_array_length(coalesce(source_refs,'[]'::jsonb)) > 1 order by slug limit 8"
|
||
for id in $(cat /tmp/wiki_e2e_id_b) $(cat /tmp/wiki_e2e_id_c) 9be3e0fa-e699-4a8e-be0c-0d934ee33294; do
|
||
echo " ES $id count=$(prod_es_count "$id")"
|
||
done
|
||
|
||
echo "### 5. 撤权其中一篇(doc b),验证共贡页面保留、专属页面消失、其它文档不受影响"
|
||
release "$(cat /tmp/wiki_e2e_id_b)" withdraw "wiki-e2e-5doc-w1" | tail -5
|
||
echo "--- 生产端证据(撤权后)"
|
||
prod_sql "select id||' enable='||enable_status from knowledges where knowledge_base_id='$KB' order by enable_status, id"
|
||
prod_sql "select 'wiki_pages='||count(*) from wiki_pages where knowledge_base_id='$KB'"
|
||
prod_sql "select 'folders='||count(*) from wiki_folders where knowledge_base_id='$KB'"
|
||
echo "还有引用被撤权文档的页面(应为 0):"
|
||
prod_sql "select count(*) from wiki_pages where knowledge_base_id='$KB' and source_refs::text like '%$(cat /tmp/wiki_e2e_id_b)%'"
|
||
echo "共贡页面是否仍在:"
|
||
prod_sql "select slug||' <- '||source_refs::text from wiki_pages where knowledge_base_id='$KB' and jsonb_array_length(coalesce(source_refs,'[]'::jsonb)) > 0 order by slug limit 8"
|
||
echo "ES 分片:"
|
||
for id in $(cat /tmp/wiki_e2e_id_b) $(cat /tmp/wiki_e2e_id_c); do echo " $id count=$(prod_es_count "$id")"; done |