feat(wiki): 監控目錄頁改走專用存取庫,比對鍵改用裸 HASH

What:MONITOR_CONTENTS 改由 wiki-repo CONTENTS 解析並透過 wiki-contents.sh
upsert 寫入,MONITOR_{HASH} 仍走 wiki-repo MONITOR。目錄頁新增一欄裸 HASH 當
比對鍵,第一欄的絕對網址連結留給人看。主機名一律取短名。

Why:目錄頁集中之後兩頁不再同庫,[[...]] 只在同一個 wiki 內解析,連結必須改絕對
網址。比對鍵原本是含網址的儲存格,換主機、換存取庫或 URL 編碼有差就比對不到,
巡檢每 15 分鐘寫一次,重複列會累積得很快。

How:目錄頁解不出存取庫時不再中止巡檢——那一頁只是索引,內容頁寫成就照樣寫心跳。
內容頁寫不成仍然中止且不寫心跳,自咬環的前提沒有鬆動。

Who:jsc-assist
This commit is contained in:
2026-09-02 11:01:51 +08:00
parent d349a76b9c
commit 4bf99dde76
10 changed files with 134 additions and 61 deletions
+37 -5
View File
@@ -74,6 +74,22 @@
# 軌跡留在摘要表:一輪一列,看得出是從哪一輪開始壞的。完整內容只留最新一輪,因為頁面要能
# 讀完才有人讀。
#
# --- 目錄頁與內容頁分屬兩個存取庫 ---
#
# 內容頁 MONITOR_{HASH} 住 MONITOR 那個存取庫,目錄頁 MONITOR_CONTENTS 住 CONTENTS 那個
# 專用存取庫,兩條解析鏈不互相退讓。所以目錄頁那一列指向內容頁的連結不能用 [[...]]:那種
# 連結只在同一個 wiki 裡解得開,跨庫是死連結,畫面上還看不出壞掉,要用絕對網址。
# 絕對網址要等內容頁真的寫進去才查得到(gitea.sh wiki-url 讀的是 API 回的 html_url),
# 而 collect 跑在寫入之前,這裡查不到。所以這支只把列組好、網址留佔位,換字交給呼叫端。
#
# --- 目錄頁的比對鍵是裸 HASH,不是那個連結 ---
#
# 目錄頁那一列另外留一欄裸 HASH(純文字、不帶連結),upsert 就拿那一欄當鍵。wiki-contents.sh
# 比對的是整格文字,拿含網址的連結當鍵太脆:GITEA_HOST 換掉、JSC_WIKI_REPO_MONITOR 換過存取
# 庫、Gitea 對頁名的網址編碼有差,整格文字就變了,鍵對不上就走附加那一支,同一台機器多出第二
# 列,舊列從此不再更新。這一頁每 15 分鐘寫一次,重複列累積得很快。裸 HASH 只由
# {主機名}/{登入帳號} 決定,上面三件事都動不到它。
#
# --- collect 的輸出 ---
#
# stdout 是 key=value,一行一個鍵,供呼叫端逐行取值。監控頁要用的 markdown 不印在
@@ -95,7 +111,9 @@
# summary_file= 「近 24 輪摘要」那一塊,表格裡先放本輪這一列,舊頁的資料列接在下面
# summary_row_file= 只有本輪那一列,方便直接插到既有表格最上面
# newpage_file= MONITOR_{HASH} 不存在時要建的整頁內容,三塊都已經排好
# contents_file= MONITOR_CONTENTS 那一列的欄位值
# contents_file= MONITOR_CONTENTS 那一列的欄位值。row= 就是整列 markdown,第一欄是連結,
# 網址的位置留 {監控頁絕對網址} 佔位,由呼叫端換掉,理由見下一段;第二欄是
# 裸 HASH,upsert 拿那一欄當鍵,理由見再下一段
#
# 環境變數:
# JSC_HOME 助理狀態檔的根目錄,預設 ~/.jsc
@@ -665,14 +683,15 @@ compose() {
printf '> 這頁固定三塊:本頁基本資料、最新一輪、近 24 輪摘要。\n'
printf '> 最新一輪每輪整塊換掉;摘要表一輪一列往上疊,只留 24 列;基本資料建頁時寫一次就不動。\n'
printf '> 完整內容只留最新一輪,頁面才讀得完;軌跡留在摘要表,看得出是從哪一輪開始壞的。\n'
printf '> 目錄頁 `MONITOR_CONTENTS` 只更新自己那一列,別台機器的列一個字都不動。\n\n'
printf '> 目錄頁 `MONITOR_CONTENTS` 在 `JSC_WIKI_REPO_CONTENTS` 解出的專用存取庫,和這頁不同庫。\n'
printf '> 那一頁只更新自己那一列,別台機器的列一個字都不動,寫入交給 `jsc-gitea/tools/wiki-contents.sh upsert`。\n\n'
printf '```mermaid\nflowchart LR\n'
printf ' A[巡檢一輪] --> B[收攏四項結果]\n'
printf ' B --> C[讀回舊頁]\n'
printf ' C --> D[換掉最新一輪那一塊]\n'
printf ' D --> E[本輪摘要列插到表格最上面,截到 24 列]\n'
printf ' E --> F[整頁寫回]\n'
printf ' F --> G[更新 MONITOR_CONTENTS 自己那一列]\n'
printf ' F --> G[wiki-contents.sh upsert 更新目錄頁自己那一列]\n'
printf ' G --> H[最後才寫心跳]\n'
printf '```\n\n'
printf '## 本頁基本資料\n\n'
@@ -695,8 +714,15 @@ compose() {
printf 'last_patrol=%s\n' "$AT"
printf 'tasks_total=%s\n' "$TASKS_TOTAL"
printf 'tasks_failing=%s\n' "$TASKS_FAILING"
printf 'row=| [[%s]] | %s | %s | %s | %s | %s | %s |\n' \
"$PAGE" "$HOST" "$USER_NAME" "$HEARTBEAT_STATE" "$AT" "$TASKS_TOTAL" "$TASKS_FAILING"
printf 'hash=%s\n' "$HASH"
# 第一欄是連結,網址留佔位由呼叫端換掉,理由見檔頭「目錄頁與內容頁分屬兩個存取庫」。
# 連結文字先寫死成頁名:頁名這裡就知道,只有網址要等內容頁寫成才查得到。
# 第二欄是裸 HASH,upsert 拿它當鍵。鍵不能用第一欄那個連結:那一格含 GITEA_HOST 與頁名的
# 網址編碼,主機位址、存取庫或編碼一變,整格文字就變了,鍵對不上就每輪多附一列。裸 HASH
# 只跟 {主機名}/{登入帳號} 有關,那三件事都動不到它。
printf 'row=| [%s](%s) | %s | %s | %s | %s | %s | %s | %s |\n' \
"$PAGE" '{監控頁絕對網址}' "$HASH" "$HOST" "$USER_NAME" "$HEARTBEAT_STATE" "$AT" \
"$TASKS_TOTAL" "$TASKS_FAILING"
} >"$RD/contents.tsv"
return 0
}
@@ -725,7 +751,13 @@ case "$CMD" in
[ -n "$TRIGGER" ] || { if [ "${JSC_CLI:-}" = cron ]; then TRIGGER='排程'; else TRIGGER='手動'; fi; }
case "$TRIGGER" in 排程|事件|手動) ;; *) usage ;; esac
ROUND="$(date +%s)-$$"
# 主機名一律取短的:第一個小數點之前那一段。CHECK_{HASH} 的雜湊來源同樣是
# {主機}/{帳號},但那一邊由模型自己填,填進去的多半是短主機名;這一邊如果拿到 FQDN,
# 同一台機器就會算出兩個雜湊、開出兩張頁,而且兩張都看起來是對的。
# 不用 hostname -s:BusyBox 與部分系統沒有這個旗標,切字串到處都成立。
HOST=$(hostname 2>/dev/null || uname -n 2>/dev/null || printf 'unknown')
HOST="${HOST%%.*}"
[ -n "$HOST" ] || HOST='unknown'
USER_NAME="${USER:-$(id -un 2>/dev/null || printf 'unknown')}"
AT=$(date '+%Y-%m-%d %H:%M')