把知識庫 ingest 從 standalone drainer(誤用 Service Bindings)重表達為 cypher workflow:
- workflow.yaml(Phase 0 cron drain):watch_cron→load_cursor→list_cards→pick_card(code)
→fetch_card→parse_card(code)→upsert_entry→save_cursor→post_envelopes→post_one_envelope。
線性 pipe,跨-worker 全走 cypher binding(零件節點),零 service binding。
- workflow.delta.yaml(Gitea webhook 穩態):collect_changed(code)→foreach card→fetch/parse/upsert/foreach envelope。
- code/kbdb/graph 接法:code=canonical `code` 零件(arcrun-code);kbdb/graph=http_request 零件打
/entries/ingest、/triplets/ingest(server 端冪等);Gitea=http_request。
- 平台端最小補丁(各需 gated 部署):
1) cypher-executor component-loader:WASM_HTTP_RUNNER_IDS 加 'code'(canonical→arcrun-code,cypher binding 正解)。
2) kbdb base:POST /entries/ingest(page_name+content_hash 冪等 upsert,對稱 graph /triplets/ingest;
因 flow DSL 無資料條件分支,把 create/patch/skip 冪等推到 server 端)。
- drainer/DEPRECATED.md:標舊 standalone worker 退役計畫(新版穩定後 wrangler delete)。
- DEPLOY.md:部署順序、cron/webhook 掛法、subdomain 對齊、驗收與退役。
本輪不部署(待總管/leo 審架構)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJiLCRUU2o3aSpPEzVCt2o
5.8 KiB
km-wiki-ingest — 部署(cypher workflow 版,走 cypher binding)
架構(D28):知識庫 ingest =跑在 cypher-executor 上的 workflow,跨-worker 呼叫全走 cypher binding(零件節點,由 component-loader 解析),零 Service Bindings。 汰換舊的 standalone
arcrun-km-wiki-drainer(drainer/,已誤用 service binding → 見drainer/DEPRECATED.md)。本輪不部署(等總管/leo 審架構)。以下是過閘後的部署順序。
0) 先決條件(兩個平台端小改,皆本分支已含,需各自 gated 部署)
這兩處是「讓 workflow 能純走 cypher binding」的最小平台補丁,不是 ingest 專屬邏輯:
-
cypher-executor:
code零件進 loader 白名單- 檔:
cypher-executor/src/lib/component-loader.ts→WASM_HTTP_RUNNER_IDS加'code'(本分支已加 1 行)。 - 效果:workflow 節點
component: code→ 解析成arcrun-code.{WORKER_SUBDOMAIN}.workers.dev(cypher binding)。 - 部署:
cd cypher-executor && npx wrangler deploy(要 leo 過閘;動到共用 executor)。 - 替代(不改 executor):把兩個 workflow 裡
component: code改成 code 的完整 URLcomponent: "https://arcrun-code.<subdomain>.workers.dev"(走 loader step 2 外部 URL)。省一次 executor 部署, 但少了「canonical 零件」的乾淨語義。建議用白名單版(這才是 D28 說的 cypher binding)。
- 檔:
-
KBDB base:
POST /entries/ingest(server 端冪等 upsert)- 檔:
kbdb/src/routes/entries.ts(本分支已加)。語義對稱 graph 的/triplets/ingest: page_name 當鍵、content_hash同 → skip、不同/無 → update、無則 create。 - 為何需要它:cypher 的 flow DSL 無資料條件分支(只有 ON_SUCCESS/ON_FAIL/FOREACH), 無法在 workflow 內做「查→比對→create 或 patch」三岔。把冪等推到 server 端,workflow 只打一發。
- 部署:
cd kbdb && npx wrangler deploy(要過閘)。
- 檔:
⚠️ subdomain 對齊:兩個 workflow 內的 URL 用
uncle6-me(官方WORKER_SUBDOMAIN,見cypher-executor/wrangler.toml)。 若你的 arcrun-kbdb / kbdb-graph-plugin / arcrun-code 部在別的 workers.dev subdomain(例leo21c), 把兩檔的 URL 一起改。舊 standalone drainer 誤用leo21c是坑之一。
1) CLI 設定
# self-hosted(namespace 明碼分區):
acr config set mode self-hosted
acr config set cypher_url https://cypher.arcrun.dev # 或你自架的 executor
echo "NAMESPACE=leo" >> .env
# standard(平台多租戶):acr init 取 api_key
2) 設 Gitea token(機密;節點以 {{credential.gitea_token}} 引用)
acr creds set gitea_token <你的 GITEA_TOKEN> # 讀 Leo/notes 用
graph 的
X-Arcrun-API-Key: leo是 namespace 字串(非機密),已內嵌節點,不需設 credential。
3) 部署 Phase 0 drain(cron 觸發)
acr push workflow.yaml
watch_cron的cron_expr: "*/2 * * * *"會被webhooks-named的extractCronExpr抓出, 寫進cron-idx:_all;cypherscheduled()每分鐘比對觸發本 workflow(不需另設 CF cron)。- 游標不需 seed:首跑
load_cursorGET 回空 →pick_card從頭;save_cursor首 tick 自動 create。 - 手動補跑一 tick(驗收):
acr run km_wiki_ingest_drain
4) 部署穩態 delta(Gitea webhook 觸發)
acr push workflow.delta.yaml
- 取得 trigger URL(self-hosted 例):
https://cypher.arcrun.dev/webhooks/named/leo/km_wiki_ingest_delta/trigger - Gitea repo
Leo/notes→ Settings → Webhooks → Add Webhook → Gitea:- Target URL:上面的 trigger URL
- Content-Type:
application/json - Trigger:Push events
- (standard 模式改帶
X-Arcrun-API-Keyheader;self-hosted 免 header,namespace 在 path)
- 這是 Gitea→Cloudflare(cypher),非 GitHub Actions → 不觸 GitHub flag(D4/D20)。
5) 驗收
# entry 落地?
curl -s "https://arcrun-kbdb.uncle6-me.workers.dev/entries?owner_id=leo&entry_type=wiki_card&limit=5" | jq '.count'
# triplet 落地?
curl -s "https://kbdb-graph-plugin.uncle6-me.workers.dev/graph?owner_id=leo" | jq '.nodes|length'
# 游標?
curl -s "https://arcrun-kbdb.uncle6-me.workers.dev/entries?owner_id=leo&page_name=cursor:km_wiki_ingest_drain:Leo/notes" | jq '.entries[0].content'
冪等自證:連跑兩次 acr run km_wiki_ingest_drain,第二次同卡 entry action:skipped、graph per-source no-op。
6) 舊 standalone drainer 退役
- 全 drain 完 + delta webhook 穩定收斂後,退役
arcrun-km-wiki-drainer:wrangler delete arcrun-km-wiki-drainer。 - 保留
drainer/原始碼一個週期(含DEPRECATED.md)供對照,確認新版逐卡輸出與舊版一致再刪。 - 見
drainer/DEPRECATED.md。
節點圖速覽
drain(cron):watch_cron(cron) → load_cursor(http GET kbdb) → list_cards(http GET Gitea tree)
→ pick_card(code) → fetch_card(http GET Gitea raw) → parse_card(code)
→ upsert_entry(http POST kbdb /entries/ingest) → save_cursor(http POST kbdb /entries/ingest)
→ post_envelopes(foreach) → post_one_envelope(http POST graph /triplets/ingest)
delta(webhook):collect_changed(code) →〔對每個 card〕→ fetch_card_d → parse_card_d(code)
→ upsert_entry_d(http) → post_envelopes_d(foreach) → post_one_envelope_d(http)
零件對應的 cypher binding:code→arcrun-code;http_request→arcrun-http-request(打 Gitea/kbdb/graph);
cron→觸發登記;foreach_control→平台 logic primitive(唯一允許的 service-binding 用法:零件等級,非本工作流編排)。
全程無工作流等級的 service binding。