地端 Edge Workers
在地端 TeamSync 套件上,Edge Workers 是選用的附加元件。後端依 EDGE_WORKERS_PROVIDER 選擇 Edge Worker provider:cloudflare(預設,即執行於 Cloudflare Workers for Platforms 的 TeamSync 雲端)或 onprem(部門 Worker 跑在套件內自架的 workerd 上)。其他任何值都是設定錯誤(edge_workers_provider_invalid:EDGE_WORKERS_PROVIDER must be 'cloudflare' or 'onprem')。雲端 runtime 見架構;本頁描述後端 5.21.0 的地端 runtime,先寫給 Worker 作者與串接方,再寫給負責套件的維運人員。
保持不變的部分
- Worker 專案、builder、成員 API、UI、生成的 OpenAPI 文件、存取模式、簽章通道與公開通道,以及 release generation 檢查,都與 TeamSync 雲端相同。
- builder 產出的 bundle 逐位元組原樣執行。儲存 binding 同樣是
TEAMSYNC_DEPARTMENT_STORAGE→ SQLite Durable Object classTeamSyncDepartmentStorage,資料存在 host 的本機磁碟。 - 每個請求都由同一份 dispatcher 程式碼回答,因此斷言檢查、body 與 query 上限、錯誤信封(
{code, message, requestId},附cache-control: no-store與x-teamsync-request-id)以及公開通道的 CORS header 都與雲端相同。 fetch()是唯一的對外原語。Worker 程式碼無法使用原始 TCPconnect():bundle 不能匯入cloudflare:sockets(builder 以source_import_forbidden拒絕)。
附加元件的運作方式
docker-compose.edge-workers.yaml 為套件加上三個容器:
| 容器 | 角色 |
|---|---|
edge-host | edge-hostd(PID 1),加上每個部門 Worker 一個釘選版本的 workerd 行程(各自使用獨立的使用者 id),以及一個為未知 Worker 回應的 fallback 行程。workerd 1.20260924.1、Node 24.21.0。 |
edge-gateway | 原版 nginx:1.28-alpine relay;進入 edge-host 的唯一途徑。後端經 http://edge-gateway:8080 呼叫它,用於簽章通道呼叫、部署與控制呼叫。 |
edge-artifacts | 專用的 S3 相容儲存,存放專案壓縮檔與 bundle(bucket edge-worker-artifacts);不對外公開任何連接埠。 |
edge-host 只連在內部的 edge_control 網路(預設子網路 172.31.253.0/29)與 edge_egress 網路上,從不連到套件網路:Worker 程式碼無法連到 MySQL、Redis、Qdrant、MinIO、edge-artifacts 或後端。地端沒有 dispatch namespace;outbox 資料列改帶部署範圍 onprem:<scope id>(見架構)。
公開 URL 與用戶端 IP
| 項目 | 地端的值 |
|---|---|
| 公開 URL | <EDGE_WORKERS_PUBLIC_BASE_URL>/public/<script>,即 https://<kit host>/edge/public/dw-<48 hex>;API 的公開 URL 路由回傳它。base 必須是 HTTPS 且路徑恰為 /edge,否則該路由回 503 Department Worker public URL is unavailable。套件的 HOST 不是 HTTPS 時,安裝程式會拒絕。 |
速率限制(套件 nginx,/edge/public/) | 每個用戶端位址每秒 50 個請求、突發 100;超出的請求得到 nginx 自己的純文字 429(不是 JSON 信封)。 |
| 請求 body | 套件 nginx 與 relay 接受最多 6 MiB;dispatcher 自己的 1 MiB 請求 body 上限照樣適用,與雲端相同。 |
| 代理逾時 | 套件 nginx:連線 5 秒,送出/讀取 75 秒。relay:連線 5 秒,送出/讀取 70 秒。 |
| 用戶端 IP | 套件 nginx 看到的位址($remote_addr)。nginx 會覆寫 X-Real-IP、X-Forwarded-For、CF-Connecting-IP 與 True-Client-IP,用戶端自己送來的這些 header 會被丟棄,因此 IP 允許清單類的存取模式比對的就是這個位址。套件前方若有 NAT 或負載平衡器,所有呼叫者都會共用它的位址。 |
request.cf | 地端沒有地理位置或機器人偵測資料。 |
執行期限制
雲端的每次呼叫 CPU 上限在地端不適用;每次呼叫改用牆鐘時間預算,記憶體與儲存則以每個 Worker 行程為單位設上限。雲端的值見限制。
| 限制 | 地端預設(環境變數、範圍) | 超過時 |
|---|---|---|
| 每次呼叫的牆鐘時間 | 30 000 ms(EDGE_HOST_INVOCATION_TIMEOUT_MS,最大 300 000;無效值退回 30 000) | 429 worker_limit_exceeded Worker execution limit exceeded(與雲端 CPU 上限相同的信封)。 |
| CPU 看門狗 | 每 1 秒做一次健康探測,逾時 1 秒;連續 2 次失敗 | 該 Worker 行程被終止並重新啟動。10 分鐘內 3 次 → 隔離 5 分鐘,每次加倍,最長 1 小時;隔離中的 Worker 回 503 worker_unavailable。新的啟用或 edge-hostctl clear-quarantine 會結束隔離。 |
| JavaScript heap | 128 MiB(EDGE_HOST_WORKER_HEAP_MB,16–4096) | 行程致命錯誤:Worker 重新啟動;進行中的請求得到 502 worker_execution_failed(若回應 header 已送出則連線被中斷)。 |
| 常駐記憶體 | 512 MiB(EDGE_HOST_WORKER_RSS_MB,32–65536),每 1 秒檢查 | 行程被終止並重新啟動。 |
| 每個 Worker 的儲存 | 2 GiB(EDGE_HOST_WORKER_STORAGE_GB;純數字代表 GiB,也可寫成 512MiB 這類大小),每 10 秒量測 | Worker 被停止(503 worker_unavailable),資料保留;部署以 edge_host_storage_exceeded 失敗,直到維運人員調高預算(edge-hostctl set-budget)。 |
| 資料檔案系統水位線 | 可用空間維持在 max(10 %, 5 GiB) 以上(可用 EDGE_HOST_DISK_WATERMARK_BYTES 覆寫),每 1 秒檢查 | 成長最快的 Worker 若自身成長占下降量至少一半,就被停止;否則 host 回報 edge_host_disk_low。以 edge-hostctl resume 恢復。 |
| 子請求 | 500:簽章斷言的 limits.subrequests(後端 EDGE_WORKERS_LIMIT_SUBREQUESTS),公開通道則為 EDGE_WORKER_SUBREQUESTS。以每個 Worker 行程為單位共用:每個執行中的呼叫把自己的額度加進同一個池,沒有呼叫在執行時池子歸零。 | Worker 的 fetch() 拋出 Too many subrequests (TeamSync on-prem subrequest limit);handler 未攔截時,生成的 runtime 回 500 worker_execution_failed。 |
| 日誌 | 每個 Worker 每秒 200 行、256 KiB(EDGE_HOST_LOG_LINES_PER_SECOND、EDGE_HOST_LOG_BYTES_PER_SECOND),突發 ×2 | 超出的行被丟棄;每秒一行 worker_log_dropped 計數。 |
| 行程/開啟檔案 | 每個 Worker 256 個(EDGE_HOST_WORKER_NPROC)/每個行程 4096 個(EDGE_HOST_WORKER_NOFILE) | 作業系統資源上限(RLIMIT_NPROC/RLIMIT_NOFILE)。 |
| 每台 host 的 Worker 數 | 50(EDGE_HOST_MAX_WORKERS,由安裝程式依 --edge-workers-max 寫入) | 再多一個 Worker 的首次部署以 edge_host_capacity_exhausted 失敗。 |
| Bundle 大小 | 1 B 到 5 MiB | 部署以 edge_host_release_too_large 失敗。 |
| 相容日期 | 不得晚於釘選 workerd 的日期:5.21.0 為 2026-09-24 | 部署以 edge_host_compatibility_date_unsupported 失敗;格式錯誤的日期以 edge_host_compatibility_date_invalid 失敗。內附範本使用 2026-08-14。 |
簽章斷言中的 CPU 值(後端 EDGE_WORKERS_LIMIT_CPU_MS)在地端沒有作用:地端 entry 會忽略它。每次部署都會重新啟動 Durable Object:舊行程停止,新行程在同一份儲存上啟動,新舊版本不會同時執行。
對外連線
Worker 的 fetch() 可到達網際網路與客戶的區域網路,但排除以下固定拒絕清單:
| 拒絕的範圍 | 原因 |
|---|---|
169.254.0.0/16、fe80::/10 | 鏈路本地位址,包含雲端 metadata 位址 |
127.0.0.0/8、::1/128 | 迴路位址 |
edge 控制子網路(預設 172.31.253.0/29) | 附加元件的內部控制網路 |
套件的服務因為 edge-host 不在它們的網路上而無法連到;套件自己的公開位址(它的 nginx)則和任何區域網路用戶端一樣可以連到。TLS 信任公用瀏覽器 CA,加上可選的站台 CA bundle /etc/edge-host/ca/extra-ca.pem(以 setup-edge-workers-onprem.sh --apply --extra-ca-certs <PEM> 安裝;bundle 必須含有 CA:TRUE 的簽發者)。主機名稱驗證維持開啟;自簽的 CA:FALSE 伺服器憑證會以 TLS peer's certificate is not trusted 失敗。
請求路由與錯誤
host 依斷言中的 script 名稱路由簽章通道呼叫,依路徑路由 /public/<script>/…。它自己的回應使用 dispatcher 的信封;在 /public/ 上附帶 dispatcher 的 CORS header。見錯誤。
| 情況 | 狀態 | code/message |
|---|---|---|
| 已退役、未知或從未啟用的 Worker(斷言驗證後由 fallback 行程回應) | 404 | worker_not_found/Worker not found |
| Worker 正在啟動、重新啟動或切換到新 release | 暫留後服務 | 請求最多等待 EDGE_HOST_HOLD_MS(預設 30 秒,1000–120000 ms)。 |
| 暫留逾時,或暫留上限已滿(每個 Worker 256 個請求、每個請求 1 MiB body、每個 Worker 16 MiB body、總計 64 MiB) | 503 | worker_unavailable/Worker unavailable |
| Worker 被隔離或因儲存而停止 | 503 | worker_unavailable/Worker unavailable |
| 回應 header 送出前就連不到 Worker 行程 | 502 | worker_execution_failed/Worker execution failed |
| 超過牆鐘時間預算 | 429 | worker_limit_exceeded/Worker execution limit exceeded |
| 套件 nginx 的公開速率限制 | 429 | nginx 的純文字回應 |
重新部署時,host 會暫留該 Worker 的請求,而不是讓新舊版本並行。把 503 worker_unavailable 當成「稍後重試」。
部署結果
部署使用與雲端相同的 API 與狀態(錯誤)。地端 provider 會在修訂版與部署票證上記錄以下 error_code:
error_code | 類別 | 原因 |
|---|---|---|
edge_host_release_put_failed | 可重試 | 上傳到 host 時傳輸失敗,或得到不確定的回覆。 |
edge_host_host_busy、edge_host_host_maintenance | 可重試 | host 回 503 host_busy/host_maintenance(重複的 host 為原文)。 |
edge_host_fenced | 延後 | 備份圍欄 開啟中:部署回到 pending,error_message 為 activation deferred by backup fence,不延遲,且不計入嘗試次數。 |
edge_host_config_invalid | 終止 | host 拒絕後端的憑證(401/403)。 |
edge_host_release_digest_mismatch、edge_host_compatibility_date_invalid、edge_host_compatibility_date_unsupported、edge_host_release_too_large | 終止 | host 拒絕上傳(422)。 |
edge_host_release_invalid | 終止 | 新 release 的 canary 或啟動失敗;前一個 release 繼續服務。 |
edge_host_release_missing | 終止 | 啟用時 host 上已沒有該 release。 |
edge_host_script_retired | 終止 | Worker 已退役(部門刪除時仍在佇列中的部署也是)。 |
edge_host_storage_exceeded | 終止 | Worker 超過儲存預算。 |
edge_host_capacity_exhausted | 終止 | 已設定的 Worker 數已達 EDGE_HOST_MAX_WORKERS。只有這個終止代碼會同時公開 error_message:The host's Worker capacity is reached; re-run setup with a larger --edge-workers-max。既有 Worker 的重新部署不計入。 |
edge_host_activate_uncertain、edge_host_fence_diverged | 不確定 | 啟用回覆遺失,且 90 秒的 host 回讀無法證明結果。公司管理者可以修復該票證。 |
啟用回覆遺失時,後端會回讀 host 最多 90 秒(每次間隔 1 秒),只有在 host 顯示該部署的 fencing token 與 release 摘要時才認定啟用成功。啟用後的就緒檢查方式與雲端相同。
維護 epoch 與還原保護
維運作業會透過 API 擋下部署與修復。POST /private/module/edge-workers/worker/deployments 與 POST /private/module/edge-workers/company/departments/{department_id}/repairs 會回 409,detail 是純字串:
| 狀態 | 部署與修復 | 其他影響 |
|---|---|---|
| resync epoch 進行中(或維護資料列不存在) | 409 edge_workers_maintenance | 公開流量照常。 |
| 備份圍欄 開啟中 | 接受(202);啟用等到 fence 結束 | 無。 |
| 還原保護開啟中 | 409 edge_workers_restore_pending | 每個 Worker 都在 host 上退役,因此公開 URL 回 404 worker_not_found。後端對 host 的呼叫回 503:呼叫 Department Worker gateway is unavailable、執行期設定 Department Worker runtime config is unavailable、機密 Department Worker secrets are unavailable、存取政策 Department Worker access policy is unavailable、操作設定 Department Worker operation settings are unavailable。公開 URL 路由仍會回應。 |
TeamSync 雲端上永遠不會出現這些 409。
啟用附加元件
附加元件只隨 -edge 與 -full 套件包提供。在套件外層資料夾執行 ls system/scripts/setup-edge-workers-onprem.sh 確認;檔案不存在時,需要改用帶有此附加元件的套件包。啟用會重新啟動套件的服務,之後也無法再使用一鍵升級(見下方升級說明)。
cd ~/TeamSync
./system/scripts/teamsync.sh enable edge-workers # first enable: no questions; uses the defaults
cd ~/TeamSync/system
./scripts/setup-edge-workers-onprem.sh # interactive: Enter enables
./scripts/setup-edge-workers-onprem.sh --apply # enable, re-apply after an upgrade, or resize
./scripts/setup-edge-workers-onprem.sh --doctor # read-only check: PASS / WARN / FAIL per line新機器可在安裝時一併啟用:./scripts/deploy-single-node.sh ... --with-edge-workers --edge-workers-max 50 --edge-data-dir <dir>。沒有 --apply(或 --yes)且沒有終端機時,安裝程式只做預覽。成功時印出 已啟用 Edge Workers。 / Workers enabled. 附加元件已開啟時,teamsync.sh enable edge-workers 會先執行 --doctor,只有在終端機中回答 y 才會重新套用。
| 旗標 | 意義 |
|---|---|
--apply | 啟用、升級後重新套用,或調整容量。 |
--yes | 不詢問直接啟用(隱含 --apply)。 |
--edge-workers-max N | Worker 容量,1 到 1000 的整數(預設 50;重跑時沿用目前的值)。沒有終端機時超出範圍:--edge-workers-max 請填 1 到 1000 的整數,例如 50。 / --edge-workers-max must be an integer from 1 to 1000, e.g. 50.(以 2 結束);在終端機中會重新詢問。 |
--edge-data-dir DIR | 把 Worker 資料與 host 狀態放在 DIR/data 與 DIR/state;建議放在獨立的磁碟或分割區。 |
--control-subnet CIDR | 內部 edge_control 網路:/29 或更大的私有 IPv4 網段(預設 172.31.253.0/29)。 |
--extra-ca-certs PATH | Worker fetch() 額外信任的 PEM 簽發者 bundle(CA:TRUE)(預設 TEAMSYNC_EXTRA_CA_CERTS);複製到 edge-workers/ca/extra-ca.pem。 |
--rotate-key | 新的 dispatch 簽章金鑰(搭配 --apply;短暫中斷)。 |
--disable | 隱藏模組、移除公開路由、把 provider 切回 cloudflare 並停止 edge 服務(搭配 --apply;資料與金鑰保留)。 |
--doctor | 唯讀健康檢查;任何一行為 FAIL 時以 1 結束(只有 WARN 時以 0 結束)。 |
--refresh-address | 同步由網站位址衍生的設定(套件變更網址時使用)。 |
--project-name NAME | Compose 專案名稱,當堆疊是以 -p 啟動時使用。 |
-h、--help | 顯示說明。 |
未知選項或缺少值的旗標以 2 結束。--apply 依序執行:檢查(套件包、HTTPS HOST、健康的後端、套件自己的憑證:rotate-kit-credentials.sh --check 仍找到出廠值時拒絕)→ 只在缺少時產生金鑰與機密 → 啟動 edge-artifacts 並建立 bucket → 建立缺少的資料表並驗證 edge_worker_maintenance → 寫入後端 prod.env 區塊、啟動 edge-host 與 edge-gateway、重建 backend 與 worker → 執行一次 resync → 最後在 UI 顯示模組並加上 /edge/public/ nginx 路由。
端到端驗證:執行 --doctor 與 python3 scripts/edge-workers/edge-workers-proof.py --base-url https://<host> --username <company admin> --ca-file nginx/certs/certificate.crt(密碼取自 TEAMSYNC_PASSWORD)。
容量規劃
安裝程式依 --edge-workers-max(N)計算 edge-host 的記憶體上限:
mem_limit = 256 MiB (hostd) + 128 MiB (backup helper) + (N + 1) × 64 MiB + 512 MiB (one RSS cap)
| N | mem_limit |
|---|---|
| 50(預設) | 4160 MiB(pids_limit 13120) |
| 6 | 1344 MiB |
| 2 | 1088 MiB |
調整容量時重跑 ./scripts/setup-edge-workers-onprem.sh --apply --edge-workers-max <larger N>:它會重新計算記憶體上限與 EDGE_HOST_MAX_WORKERS 並重建 edge-host 與 edge-gateway,因此每個 Worker 都會重新啟動,公開請求最多暫留 EDGE_HOST_HOLD_MS(預設 30 秒)。
Worker 資料與 host 狀態預設放在 Docker volume edge_host_data/edge_host_state,與 MySQL、MinIO 在同一個檔案系統(--doctor 會對此提出警告)。專用檔案系統的大小應為:預估的 Worker 資料 + 2 × 最大的 Worker + 水位線 max(10 %, 5 GiB) + 餘裕 max(1 GiB, 2 %)。
停用
./scripts/setup-edge-workers-onprem.sh --disable --apply 會隱藏模組、移除 /edge/public/ 路由、設定 EDGE_WORKERS_PROVIDER=cloudflare、重建 backend 與 worker,停止並移除 edge-host、edge-gateway 與 edge-artifacts 容器,並把附加元件從 COMPOSE_FILE 移除(每晚的備份不再包含它)。資料、金鑰與 volume 都會保留;它會印出 已停用 Edge Workers;資料與金鑰保留。 / Workers are off; data and keys are kept. 之後執行 --apply 即可重新啟用。只加 --disable 時,會先詢問(在終端機中)或只做預覽。
維運指令
Resync
resync 讓 host 只服務資料庫所記載的內容。可以安全重跑;重跑會接續同一個 epoch。
./scripts/edge-workers/resync.sh [--accept-edge-data-mismatch | --abort-diverged | --edge-absent]這個包裝腳本在一次性的 backend 容器中執行 resync。它先取得一把鎖(同時執行第二個會失敗),開啟維護 epoch(期間部署與修復回 409 edge_workers_maintenance;公開流量照常),接著最多執行 3 輪:結清被攔下的部署、把每個存活 Worker 在 host 上的 release 收斂到資料庫的目前版本(從驗證過的產物重新上傳遺失或損壞的 release)、讓其他所有仍在服務的 Worker 退役、驗證。
| 旗標 | 作用 |
|---|---|
| 無 | 修復偏差,讓資料庫與 host 重新配對。 |
--edge-absent | 還原的備份沒有 Worker 資料:開啟還原保護,並讓 host 上的每個 Worker 退役。不能與 --accept-edge-data-mismatch 並用。 |
--accept-edge-data-mismatch | 結束還原保護;為每個 Worker 寫入 edge_worker.resync 稽核資料列,reason_code 為 edge_data_mismatch_accepted(租戶可見)。只在確認備份與差異後使用。 |
--abort-diverged | 對 3 輪後仍偏差的 Worker:其目前版本變成 failed(edge_host_release_lost;還原保護期間為 edge_host_resync_failed;訊息 Edge Worker release was lost during resync),Worker 變成沒有目前版本的 draft,被攔下的部署以 edge_host_resync_failed 失敗。可與上述任一旗標並用。 |
被攔下的部署只有在 host 證明其 token 與摘要、產物驗證通過且就緒檢查成功時才會完成;否則以 edge_worker_deleted、edge_host_resync_superseded、edge_workers_restore_pending、edge_host_resync_artifact_invalid 或 edge_host_resync_unready 失敗,由部門重新提交。每項變更都以 edge_worker.resync 稽核,actor 為 system,reason_code 為 promoted(被攔下的部署已完成)、settled_failed(被攔下的部署失敗)、edge_worker_deleted(被攔下的部署因其 Worker 已刪除而失敗)、cleared、retired、unretired、rolled_back、edge_data_held 或 edge_data_mismatch_accepted。
它只印出一行 JSON(絕不含機密):
| 結果 | 輸出 | 結束碼 |
|---|---|---|
| 已收斂 | {"diverged": [], "edge_data_hold": false, "epoch": "<hex>", "state": "idle"}(還原保護仍開啟時 edge_data_hold 為 true) | 0 |
| 未收斂 | {"epoch": "<hex>", "error": "edge_host_resync_diverged", "hint": "rerun resync or use --abort-diverged", "scripts": [...], "state": "active"};epoch 維持開啟 | 1 |
| 其他失敗 | {"state": "active", "error": "<ExceptionClass>"}(ValueError:provider 不是地端) | 1 |
| 未知選項(包裝腳本) | Unknown option: <arg> 與修復指令 ./scripts/edge-workers/resync.sh --help | 2 |
| Docker 無法使用(包裝腳本) | 訊息 | 1 |
備份圍欄
scripts/backup.sh 會在備份期間暫停部署啟用(fence),分成 begin 與 end 兩個步驟;維運人員通常不需要直接執行。
| 步驟 | 行為 | 輸出 |
|---|---|---|
begin | resync epoch 進行中、還原保護開啟中或已記錄 fence 時拒絕。否則把 host 的 fence 設到現在 + EDGE_BACKUP_FENCE_MAX 秒(預設 7200,允許 1–86400),再把 fence 記錄到資料庫。 | {"edge": "fenced", "until": <unix s>},或 {"edge": "absent", "reason": "edge_workers_maintenance"}/"edge_workers_restore_pending" |
end | 必須等 host 確認 fence 結束,才清除資料庫中的 fence;--abandon 會對 host 重試最多 30 秒。接著重新發布被延後的部署。 | {"edge": "complete", "held": true};fence 已過期、被 resync 清除或隨 edge-host 重新啟動而遺失時為 {"edge": "absent", "held": false} |
結束碼:fenced/complete 為 0,absent 為 2,任何錯誤為 1({"edge": "absent", "error": "<ExceptionClass>"})。fence 期間,部署請求照樣接受並等待(edge_host_fenced);fence 結束後立即啟用。fence 只存在 host 的記憶體中:後端每 15 秒的調節會清除 host 已不再回報的資料庫 fence。
edge-hostctl
在容器內執行,例如 docker compose exec edge-host edge-hostctl status。<script> 是 Worker 的 script 名稱 dw-<48 hex>。
| 指令 | 輸出 | 結束碼 |
|---|---|---|
health | {healthy, bootComplete, degraded};degraded 可能列出 edge_host_disk_low、edge_host_memory_headroom_low、edge_host_capacity_exceeded。也是容器的 Docker 健康檢查。 | 開機完成且 fallback 行程在執行時為 0;否則或超過 10 秒為 1 |
status | 每個 Worker 的 JSON(狀態、pid、重啟次數、儲存、隔離)、維護、fence、暫留的請求、磁碟、記憶體、備份與 hostd | 0 |
backup-worker <script> [--same-filesystem] | stdout 輸出經驗證的 Worker 儲存 tar,stderr 輸出 JSON 結果;失敗代碼 edge_host_backup_unknown_script、edge_host_backup_measure_failed、edge_host_backup_precheck_failed、edge_host_backup_copy_aborted、edge_host_backup_copy_failed、edge_host_backup_copy_invalid | 0/1 |
backup-state | stdout 輸出一致的 host 狀態 tar | 0/1 |
set-budget <script> <size> | 設定該 Worker 的儲存預算(2GiB、512MiB 或位元組數),並恢復現在已容得下的預算停止;印出 {script, budget, usage, resumed} | 0 |
resume <script> | 解除水位線或儲存停止。拒絕時印出 refused: the data filesystem is below its watermark 或 refused: the Worker is over its budget; raise it with set-budget | 0;拒絕或未恢復時為 1 |
clear-quarantine <script> | 結束隔離並重新啟動該 Worker;印出 {script, cleared} | 0 |
不帶指令時印出用法並以 2 結束;未知指令以 2 結束。指令失敗時(例如 script 名稱或大小無效)印出 error: <reason> 並以 1 結束。
備份與還原
./scripts/backup.sh(以及每晚的排程)會自動加上 Edge 部分:edge/workers/<script>.tar、edge/state.tar、edge/artifacts.tar.gz 與 edge/config.env(權限 0600)。順序:暫停啟用(fence)→ MySQL、Redis、Qdrant、MinIO → 在服務中逐一複製每個 Worker,再複製 host 狀態 → 結束 fence → 產物與設定。manifest 記錄 "edge": "complete",或附原因(記於 edge_reason)的 "edge": "absent"(例如 edge_workers_maintenance、edge_host_backup_precheck_failed、edge_host_backup_copy_aborted、fence_not_held、edge_config_incomplete)。Edge 的問題絕不會讓套件本身的備份消失:該組備份會在缺少 Edge 部分的情況下發布,backup.sh 在發布後以 2 結束。
有附加元件時,./scripts/restore.sh <version> 會先驗證每個選取的封存檔,停止 backend、worker、edge-gateway、edge-host 與 edge-artifacts,還原後啟動 edge 服務、執行 resync,並一律重新啟動 backend 與 worker。只有 manifest 寫明 edge: complete 的備份組才會還原 Edge volume。--only edge-workers 還原完整備份組的 host 狀態與 Worker 資料;--only edge-artifacts 還原產物儲存。還原的 MySQL 若沒有對應的 Edge 部分(edge: absent 的備份組、啟用附加元件前的備份組,或 --only mysql),會執行 resync --edge-absent:每個 Worker 都在還原保護下維持退役,直到還原完整的備份組,或維運人員執行 --accept-edge-data-mismatch(--only edge-workers 不會改變還原保護)。resync 未收斂時,套件仍維持運作,restore.sh 以 3 結束。
升級、金鑰輪替與網址變更
- 升級。 有附加元件的機器上,一鍵升級會停下來;請依套件的手動升級指南進行。其中 Edge Workers 步驟:新套件必須帶有附加元件;以
cp -a "$NEW/edge-workers/." edge-workers/從新套件複製edge-workers/(保留*.env與ca/extra-ca.pem),再執行./scripts/setup-edge-workers-onprem.sh --apply與--doctor。金鑰與資料都會保留並執行一次 resync;新的 workerd 版本會重新啟動每個 Worker。 - 金鑰輪替。
./scripts/setup-edge-workers-onprem.sh --apply --rotate-key建立新的 Ed25519 dispatch 金鑰,並重建edge-host、backend 與 worker;由 resync 證明新金鑰可用。Worker 呼叫會失敗幾秒。 - 網址變更。 變更套件的網站位址時,會以
--refresh-address重跑安裝程式,把EDGE_WORKERS_PUBLIC_BASE_URL改寫為新位址 +/edge(手動設定的值會保留)。公開 URL 隨之改變。
退役與資料保留
部門刪除時,provider 先清除該 Worker 的執行期機密與服務帳號憑證,再通知 host 讓該 Worker 退役;host 會先記錄退役,再停止行程。若無法通知 host,後端的 host 調節(每個 API replica 每 15 秒)會重試。同一個調節也會讓 host 上任何在資料庫中沒有存活 Worker 的已服務 Worker 退役(也涵蓋公司硬刪除),但只在資料庫與 host 已配對時(沒有 resync epoch,且 host 最後一次 resync 的 epoch 相符);未配對時什麼都不退役,並記錄 edge_host_unpaired。公開 URL 會在刪除後約一分鐘內回 404 worker_not_found,仍在佇列中的該 Worker 部署則以 edge_host_script_retired 失敗。與 provider 無關的流程見退役。
與雲端不同,地端會保留已退役 Worker 的資料:host 永遠不會清除它。每個 Worker 的 host 保留目前啟用的 release 與前兩個(加上最後一次啟用嘗試的 release,以及待完成切換仍指名的 release);更舊的 release 會被修剪。Worker 儲存只有一份:還原點就是最後一次備份。--disable --apply 會保留資料與金鑰。
產物儲存
在地端,專案壓縮檔與 bundle 存放在專用的 edge-artifacts 服務,而不是 R2:以 S3 用戶端連到 http://edge-artifacts:9000,使用 path-style 定址、區域 us-east-1、bucket edge-worker-artifacts 與 EDGE_WORKERS_ARTIFACTS_* 憑證(缺少值時以 dedicated on-prem Edge Worker artifact store is not configured 失敗)。它不對外公開任何連接埠,也不在套件公開的 /s3/ 代理之後;絕不要把它放到那裡。
環境變數
所有值都由安裝程式寫入;產生的金鑰與機密永遠不會印出。後端的其他設定見環境變數。
後端(prod.env)。 在地端,後端永遠不讀取 EDGE_WORKERS_CLOUDFLARE_*、EDGE_WORKERS_DISPATCH_ORIGIN 或 EDGE_WORKERS_R2_*。
| 變數 | 值 |
|---|---|
EDGE_WORKERS_PROVIDER | onprem(未設定或空值 = cloudflare) |
EDGE_WORKERS_ONPREM_GATEWAY_URL | 必須是 http://edge-gateway:8080 |
EDGE_WORKERS_ONPREM_SCOPE_ID | 恰好 12 個小寫 hex 字元;部署範圍為 onprem:<scope id> |
EDGE_WORKERS_HOST_AUDIENCE | teamsync-edge-host(預設) |
EDGE_WORKERS_DISPATCH_PRIVATE_KEY | Ed25519 簽章金鑰(機密) |
EDGE_WORKERS_DISPATCH_KEY_ID | 金鑰 id |
EDGE_WORKERS_DISPATCH_AUDIENCE | teamsync-department-workers |
EDGE_WORKERS_DISPATCH_ISSUER | teamsync-backend |
EDGE_WORKERS_ARTIFACTS_ENDPOINT_URL | 必須是 http://edge-artifacts:9000 |
EDGE_WORKERS_ARTIFACTS_BUCKET | edge-worker-artifacts |
EDGE_WORKERS_ARTIFACTS_ACCESS_KEY_ID、EDGE_WORKERS_ARTIFACTS_SECRET_ACCESS_KEY | 產物儲存憑證(機密) |
EDGE_WORKERS_PUBLIC_BASE_URL | https://<kit host>/edge(HTTPS,不含帳密、query 或 fragment) |
EDGE_BACKUP_FENCE_MAX | 備份圍欄 長度(秒):預設 7200,允許 1–86400 |
缺少或格式錯誤的值會以 edge_workers_provider_invalid 失敗(Edge Worker on-prem credentials are incomplete、Edge Worker on-prem scope is invalid、EDGE_WORKERS_PUBLIC_BASE_URL must be an HTTPS /edge base、<NAME> must use the kit's internal service)。
Edge host(edge-workers.env 與 compose)。 任何無效的整數或大小都會讓 hostd 在啟動時停止,但有三個值 hostd 不檢查、直接傳遞:無效的 EDGE_HOST_INVOCATION_TIMEOUT_MS 退回 30000;無效的 EDGE_WORKER_CPU_MS(1–30000)或 EDGE_WORKER_SUBREQUESTS(1–1000)會讓公開通道請求回 503 dispatcher_unavailable。
| 變數 | 預設(範圍) |
|---|---|
EDGE_WORKER_ASSERTION_PUBLIC_JWK | 必填(dispatch 公鑰) |
EDGE_HOST_CONTROL_ADDRESS、EDGE_HOST_RELAY_ADDRESS、EDGE_HOST_CONTROL_SUBNET | 必填;套件預設 172.31.253.3、172.31.253.2、172.31.253.0/29 |
EDGE_WORKER_ASSERTION_ISSUER/EDGE_WORKER_ASSERTION_AUDIENCE/EDGE_WORKERS_HOST_AUDIENCE | teamsync-backend/teamsync-department-workers/teamsync-edge-host |
EDGE_WORKER_CPU_MS | 50(會解析,但地端不強制) |
EDGE_WORKER_SUBREQUESTS | 500(公開通道) |
EDGE_HOST_INVOCATION_TIMEOUT_MS | 30000(最大 300000) |
EDGE_HOST_HOLD_MS | 30000(1000–120000) |
EDGE_HOST_HOLD_MAX_PER_SCRIPT | 256(1–10000) |
EDGE_HOST_HOLD_MAX_REQUEST_BYTES/EDGE_HOST_HOLD_MAX_SCRIPT_BYTES/EDGE_HOST_HOLD_MAX_TOTAL_BYTES | 1 MiB(最大 64 MiB)/16 MiB(最大 1024 MiB)/64 MiB(最大 1024 MiB) |
EDGE_HOST_WORKER_HEAP_MB | 128(16–4096) |
EDGE_HOST_WORKER_RSS_MB | 512(32–65536) |
EDGE_HOST_WORKER_STORAGE_GB | 2(GiB,或 512MiB 這類大小) |
EDGE_HOST_WORKER_NPROC/EDGE_HOST_WORKER_NOFILE | 256(16–65536)/4096(64–1048576) |
EDGE_HOST_MAX_WORKERS | 50(依 --edge-workers-max 寫入;hostd 接受 1–100000) |
EDGE_HOST_DISK_WATERMARK_BYTES | 未設定 = 資料檔案系統的 max(10 %, 5 GiB) |
EDGE_HOST_BACKUP_MARGIN_BYTES | 未設定 = max(1 GiB, 2 %) |
EDGE_HOST_LOG_LINES_PER_SECOND/EDGE_HOST_LOG_BYTES_PER_SECOND | 200/256 KiB |
EDGE_HOST_EXTRA_CA_FILE | /etc/edge-host/ca/extra-ca.pem |
套件 .env。 EDGE_WORKERS_CONTROL_SUBNET、EDGE_WORKERS_CONTROL_HOST_IP、EDGE_WORKERS_CONTROL_RELAY_IP、EDGE_HOST_MEM_LIMIT(預設 4160m)、EDGE_HOST_PIDS_LIMIT(預設 13120)、EDGE_HOST_STATE_SOURCE、EDGE_HOST_DATA_SOURCE(預設為具名 volume)。
Relay(edge-workers/relay.env)。 EDGE_RELAY_SECRET 必須至少 32 個 URL 安全字元;否則 relay 對每個請求都回純文字 503。