Files
Arcrun/registry/examples/km-wiki-ingest/DEPLOY.md
T
kbdb-cc c6932b0088 feat(km-wiki-ingest): 重做成跑在 cypher 上的 workflow(走 cypher binding,汰換 service-binding drainer,D28)
把知識庫 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
2026-07-06 12:59:13 +00:00

5.8 KiB
Raw Blame History

km-wiki-ingest — 部署(cypher workflow 版,走 cypher binding

架構(D28:知識庫 ingest 跑在 cypher-executor 上的 workflow,跨-worker 呼叫全走 cypher binding(零件節點,由 component-loader 解析),零 Service Bindings。 汰換舊的 standalone arcrun-km-wiki-drainerdrainer/,已誤用 service binding → 見 drainer/DEPRECATED.md)。

本輪不部署(等總管/leo 審架構)。以下是過閘後的部署順序。

0) 先決條件(兩個平台端小改,皆本分支已含,需各自 gated 部署)

這兩處是「讓 workflow 能純走 cypher binding」的最小平台補丁,不是 ingest 專屬邏輯:

  1. cypher-executorcode 零件進 loader 白名單

    • 檔:cypher-executor/src/lib/component-loader.tsWASM_HTTP_RUNNER_IDS'code'(本分支已加 1 行)。
    • 效果:workflow 節點 component: code → 解析成 arcrun-code.{WORKER_SUBDOMAIN}.workers.devcypher binding)。
    • 部署:cd cypher-executor && npx wrangler deploy(要 leo 過閘;動到共用 executor)。
    • 替代(不改 executor:把兩個 workflow 裡 component: code 改成 code 的完整 URL component: "https://arcrun-code.<subdomain>.workers.dev"(走 loader step 2 外部 URL)。省一次 executor 部署, 但少了「canonical 零件」的乾淨語義。建議用白名單版(這才是 D28 說的 cypher binding)。
  2. KBDB basePOST /entries/ingestserver 端冪等 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-hostednamespace 明碼分區):
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 draincron 觸發)

acr push workflow.yaml
  • watch_croncron_expr: "*/2 * * * *" 會被 webhooks-namedextractCronExpr 抓出, 寫進 cron-idx:_allcypher scheduled() 每分鐘比對觸發本 workflow不需另設 CF cron)。
  • 游標不需 seed:首跑 load_cursor GET 回空 → pick_card 從頭;save_cursor 首 tick 自動 create。
  • 手動補跑一 tick(驗收):acr run km_wiki_ingest_drain

4) 部署穩態 deltaGitea webhook 觸發)

acr push workflow.delta.yaml
  • 取得 trigger URLself-hosted 例): https://cypher.arcrun.dev/webhooks/named/leo/km_wiki_ingest_delta/trigger
  • Gitea repo Leo/notesSettings → Webhooks → Add Webhook → Gitea
    • Target URL:上面的 trigger URL
    • Content-Typeapplication/json
    • TriggerPush events
    • standard 模式改帶 X-Arcrun-API-Key headerself-hosted 免 headernamespace 在 path
  • 這是 Gitea→Cloudflare(cypher)非 GitHub Actions → 不觸 GitHub flagD4/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-drainerwrangler delete arcrun-km-wiki-drainer
  • 保留 drainer/ 原始碼一個週期(含 DEPRECATED.md)供對照,確認新版逐卡輸出與舊版一致再刪。
  • drainer/DEPRECATED.md

節點圖速覽

draincronwatch_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)

deltawebhookcollect_changed(code) →〔對每個 card〕→ fetch_card_dparse_card_d(code)upsert_entry_d(http)post_envelopes_d(foreach)post_one_envelope_d(http)

零件對應的 cypher bindingcode→arcrun-codehttp_request→arcrun-http-request(打 Gitea/kbdb/graph); cron→觸發登記;foreach_control→平台 logic primitive(唯一允許的 service-binding 用法:零件等級,非本工作流編排)。 全程無工作流等級的 service binding。