fix(db): split inbound truth-chain hot lookup
Some checks failed
CD Pipeline / workflow-shape (push) Has been cancelled
CD Pipeline / cancel-stale-cd (push) Has been cancelled
CD Pipeline / tests (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled

This commit is contained in:
Your Name
2026-07-01 08:45:40 +08:00
parent a6dc806d38
commit abc512a7b3
7 changed files with 245 additions and 65 deletions

View File

@@ -51165,3 +51165,27 @@ production browser smoke:
**下一步**
- rebase / push source 修法110 控制面恢復後第一個 runtime 動作是套用新版 `systemd-units-textfile-exporter.py` 或暫停舊 exporter再回讀 DBus/logind、systemd_units.prom 與 Gitea CPU。188 runner 只在 host pressure gate / queue readback 綠燈後恢復。
## 2026-07-01 — 08:44 P0 188 truth-chain source split 與 110 控制面讀回
**完成內容**
- 188 DB CPU 再次讀回仍高:`k3s-postgres-recovery=609.72%`active query 明確是 120 live API 發出的舊 `awooop_conversation_event` inbound lookup大量 `run_id::text / provider_event_id / content_preview ILIKE / source_refs JSONB` 放在同一個 `OR` predicate並產生 local parallel workers。
- 已 live 套用 content preview fallback 索引:`idx_awooop_conv_event_content_preview_trgm``idx_awooop_conv_event_project_content_preview_trgm` 均讀回 `indisvalid=true / indisready=true`
- 新增 migration source`apps/api/migrations/awooop_conversation_event_content_preview_trgm_2026-07-01.sql` / `_down.sql`,使用 `CREATE INDEX CONCURRENTLY IF NOT EXISTS``pg_trgm``btree_gin`rollback 只 drop 本 migration indexes不 drop extension。
- 修正 `apps/api/src/services/awooop_truth_chain_service.py`:把 inbound conversation event lookup 拆成逐分支查詢,先查 `run_id``provider_event_id`、各 `source_refs` JSONB key再有限度 fallback 到 `content_preview ILIKE` / fingerprint lookup移除會讓 planner 放大掃描的大型 source-envelope `OR` 查詢。
- 188 runtime 暫時降壓:`ALTER ROLE awoooi SET max_parallel_workers_per_gather=0`,取消 5 條舊 OR active query並只斷開 `192.168.0.120``awoooi_prod` 的 30 條 app DB session 讓新設定生效。rollbacksource split 部署收斂後執行 `ALTER ROLE awoooi RESET max_parallel_workers_per_gather`
- post-mitigation 讀回:`awoooi` role config 已是 `max_parallel_workers_per_gather=0`、舊 OR 查詢 local parallel workers 降為 `0`;但舊 OR query 仍有 `4` 條 active`k3s-postgres-recovery=400.19%`,所以真正完成仍需 120 部署 source split。
- 110 最新 node exporter 讀回:`node_load5=29.34``awoooi_host_load5_per_core=2.068333``node_procs_running=31``gitea=3.4019` coresSSH / scp / stdin-over-ssh 嘗試仍 timeout尚未能 live 套用新版 systemd exporter。
**本地驗證結果**
- `DATABASE_URL=postgresql+asyncpg://test:test@localhost:5432/test PYTHONPATH=apps/api python3.11 -m pytest apps/api/tests/test_awooop_truth_chain_service.py::test_fetch_truth_chain_returns_inbound_redacted_envelope_fields apps/api/tests/test_awooop_truth_chain_service.py::test_fetch_truth_chain_splits_inbound_lookup_into_index_friendly_branches apps/api/tests/test_awooop_conversation_event_hot_path_indexes.py -q``7 passed`
- `python3.11 -m py_compile apps/api/src/services/awooop_truth_chain_service.py`:通過。
- 已更新 `docs/operations/host-cpu-pressure-drain-readback-2026-07-01.snapshot.json`,保留 188 temporary DB mitigation、source split、110 control-path blocker 與 rollback。
**仍維持**
- 沒有讀 secret / token / `.env` / raw sessions / SQLite / auth沒有讀 `.runner` 內容。
- 沒有使用 GitHub / gh / GitHub API / GitHub Actions。
- 沒有重啟主機,沒有 Docker / Nginx / K3s / DB restart沒有 workflow_dispatch沒有 DROP / TRUNCATE / restore / prune。
**下一步**
- rebase / commit / push truth-chain source split讀回 Gitea queue 與 188 DB active query。若 deploy 收斂,立即 reset `awoooi` role 的 temporary `max_parallel_workers_per_gather=0`;若 110 SSH 恢復,第一動作仍是套用新版 systemd exporter 或暫停舊 exporter再回讀 systemd/logind、Gitea CPU 與 load5/core。

View File

@@ -1,7 +1,7 @@
{
"schema_version": "awoooi_host_cpu_pressure_drain_readback_v1",
"generated_at": "2026-07-01T08:19:00+08:00",
"status": "partial_110_control_path_blocked_188_drained",
"generated_at": "2026-07-01T08:44:00+08:00",
"status": "partial_188_bounded_source_fix_ready_110_control_path_blocked",
"scope": {
"hosts": ["188", "110"],
"incident_family": "post_reboot_host_cpu_pressure",
@@ -35,6 +35,14 @@
"reason": "active CD API tests were repeatedly spawning and driving production PostgreSQL CPU",
"rollback": "restart the non-110 runner only after host pressure guard and source CD gate are green",
"post_apply_readback": "runner inactive, no awoooi-cd-* containers, k3s-postgres-recovery docker stats 7.81 percent"
},
{
"host": "188",
"target_selector": "awoooi PostgreSQL role sessions from 192.168.0.120 running old awooop_conversation_event OR lookup",
"action": "set max_parallel_workers_per_gather=0 for role, cancel active old OR queries, and terminate 192.168.0.120 app DB sessions so new sessions inherit the bound",
"reason": "the live 120 API was still repeatedly issuing the pre-fix OR query and spawning parallel workers after index apply",
"rollback": "ALTER ROLE awoooi RESET max_parallel_workers_per_gather; then let the app reconnect after source split deploys",
"post_apply_readback": "rolconfig shows max_parallel_workers_per_gather=0; local parallel workers for the old query dropped to 0"
}
],
"source_fixes": [
@@ -47,6 +55,16 @@
"path": "scripts/ops/systemd-units-textfile-exporter.py",
"change": "shorten systemctl show timeout, compact error labels, stop probing after timeout budget, and add non-overlap lock",
"evidence": "pytest covers timeout budget and busy lock"
},
{
"path": "apps/api/src/services/awooop_truth_chain_service.py",
"change": "split the inbound conversation event lookup into index-friendly branches instead of one large OR predicate",
"evidence": "focused tests confirm the source_refs/content_preview branches are isolated and the old source_envelope OR pattern does not return"
},
{
"path": "apps/api/migrations/awooop_conversation_event_content_preview_trgm_2026-07-01.sql",
"change": "add bounded pg_trgm / btree_gin indexes for content_preview fallback lookup",
"evidence": "live verifier read back both trigram indexes as valid and ready"
}
],
"readback": {
@@ -64,13 +82,21 @@
"pg_dump_process": "none",
"k3s_postgres_recovery_docker_stats_percent": "7.81",
"docker_stats_textfile_k3s_postgres_recovery_cores": "0.406900"
},
"post_bounded_db_mitigation_signals": {
"awoooi_role_config": "max_parallel_workers_per_gather=0",
"active_old_or_queries": "4",
"local_parallel_workers_for_old_or_query": "0",
"k3s_postgres_recovery_docker_stats_percent": "400.19",
"remaining_root_cause": "120 live API still runs the pre-fix OR query until the source split is deployed"
}
},
"host_110": {
"signals": {
"load5_initial": "39.14",
"load5_latest": "18.85",
"node_procs_running_latest": "6",
"load5_latest": "29.34",
"load5_per_core_latest": "2.068333",
"node_procs_running_latest": "31",
"gitea_container_cpu_cores": "3.4019",
"ssh_control_path": "timeout",
"systemd_dbus_symptom": "systemd-logind pending replies exhausted; systemctl list/show timeout",
@@ -78,22 +104,25 @@
},
"not_completed_live": [
"could not apply pkill/exporter drain on 110 because SSH command sessions timeout",
"scp and stdin-over-ssh attempts to place the new exporter file timed out",
"could not restart or reexec systemd/logind because that would require a control path that is currently unavailable"
]
}
},
"verification": {
"py_compile": "passed: scripts/ops/systemd-units-textfile-exporter.py",
"py_compile": "passed: scripts/ops/systemd-units-textfile-exporter.py and apps/api/src/services/awooop_truth_chain_service.py",
"bash_n": "passed: scripts/ci/wait-host-web-build-pressure.sh scripts/ops/systemd-units-textfile-exporter.py",
"pytest": [
"scripts/ops/tests/test_systemd_units_textfile_exporter.py: 2 passed",
"scripts/ops/tests/test_systemd_units_textfile_exporter.py + ops/runner/test_cd_controlled_runtime_profile.py: 34 passed"
"scripts/ops/tests/test_systemd_units_textfile_exporter.py + ops/runner/test_cd_controlled_runtime_profile.py: 34 passed",
"truth-chain source split + content-preview migration focused suite: 7 passed"
],
"diff_check": "passed"
},
"next_actions": [
"commit and push the truth-chain source split so 120 stops issuing the old OR query",
"after deploy convergence, reset the temporary awoooi role max_parallel_workers_per_gather override",
"apply the systemd exporter source fix to 110 once SSH/control path is available",
"keep 188 non-110 runner drained until the pushed CD gate is in place and host pressure readback is green",
"continue 110 Gitea queue / awoooi-host controlled lane recovery without generic runner restore"
]
}