Skip to Content
參考資料環境變數

環境變數

Edge Workers 沒有 Pydantic settings class — 每個元件各自 os.getenv 並在呼叫點驗證。除註明外預設值皆為 ""。以下佔位符來自 example.env;實際值由 Infisical 按環境佈建。截至後端 5.22.0,後端讀取下列 EDGE_WORKERS_* 名稱(另有三個屬於維運者專用的 Worker 搬移流程、不在此說明)、三個單數的 EDGE_WORKER_* 名稱,以及 EDGE_BACKUP_FENCE_MAX。

後端 — provider 選擇

變數預設規則機密
EDGE_WORKERS_PROVIDERcloudflare去除前後空白並轉小寫;空白或未設定 → cloudflare;允許 cloudflare | onprem;其他任何值 → edge_workers_provider_invalid(EDGE_WORKERS_PROVIDER must be 'cloudflare' or 'onprem')。選了 onprem 但沒有地端套件 → edge_workers_provider_unavailable(Edge Worker on-prem provider is not installed)否

不合法的值不會被夾住。提交與部署路由回 503 Edge Worker provider is not configured,產物儲存與閘道無法使用,60 秒回收迴圈每輪都略過(Edge Worker recovery skipped: edge_workers_provider_invalid),已取得租約的部署則結算為 failed(調解模式下為 uncertain),error_code: "edge_workers_provider_invalid"。以下各節依 provider 而異:值為 cloudflare 時適用 Cloudflare 的各節,值為 onprem 時適用地端各節;地端後端從不讀取 EDGE_WORKERS_CLOUDFLARE_*、EDGE_WORKERS_DISPATCH_ORIGIN 或 EDGE_WORKERS_R2_*。

後端 — Cloudflare 控制面

變數使用者規則機密
EDGE_WORKERS_CLOUDFLARE_ACCOUNT_IDCloudflare provider、產物儲存^[0-9a-fA-F]{32}$(artifacts 側,以及自 5.22.0 起的部署目標選定,要求小寫)否
EDGE_WORKERS_CLOUDFLARE_API_TOKENCloudflare provider、孤兒報告非空;session 用 trust_env=False,proxy 永遠看不到是
EDGE_WORKERS_CLOUDFLARE_DISPATCH_NAMESPACECloudflare provider、部署 outbox、退役^[a-z0-9][a-z0-9-]{0,62}$;此環境建立新 Worker script 的 dispatch namespace。它不再用來選擇 dispatcher(見下方的環境宣告一節),而且自後端 5.22.0 起它只是預設值:既有的 Worker 仍沿用目前服務它的位置。outbox 在 Worker 的首次部署與產物清理意圖上蓋上它(去除前後空白),回收掃描認領的是共用位置加上該環境自己的舊有位置,而不只是這個值;未設定,或不是平台自己的位置之一 → 什麼都不認領,而且 Worker 的首次部署會被拒絕。兩個逐 namespace 退役確認(department.worker_script_deleted、department.worker_script_neutralized)以它們所作用的 namespace 作為 reason_code,而且此變數未設定時退役什麼都不做否

後端 — 調度閘道與簽章

變數規則機密
EDGE_WORKERS_DISPATCH_ORIGINHTTPS、無 port/path/query/憑證;hostname 標籤必須恰為 [<expected-dispatcher>, <subdomain>, workers, dev],其中 <expected-dispatcher> 由 API 的環境宣告(見下)推導。不吻合 → Edge Worker dispatcher is not configured否
EDGE_WORKERS_CLOUDFLARE_WORKERS_SUBDOMAINDNS 標籤 ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$;dispatcher origin 的第二個標籤(由閘道檢查),deploy-platform.mjs 在任何變更前對實際帳號做認證否
EDGE_WORKERS_DISPATCH_PRIVATE_KEYEd25519 PKCS8 PEM;字面 \n 序列會轉為換行。地端時它也用來簽發對 edge host 的呼叫是
EDGE_WORKERS_DISPATCH_KEY_IDASCII ≤128 → JWS kid否
EDGE_WORKERS_DISPATCH_AUDIENCEASCII ≤256 → aud否
EDGE_WORKERS_DISPATCH_ISSUERASCII ≤256 → iss;預設 teamsync-backend(也是地端 host 呼叫的 issuer)否
EDGE_WORKERS_GATEWAY_PUBLIC_URL模式為 teamsync_internal 時記錄在生成 OpenAPI 的公開 invoke base;退回 HOST + invoke 路徑;永遠不是請求的 Host header;兩者皆空 → 503否
EDGE_WORKERS_DISPATCH_PUBLIC_JWK後端從不讀取 — 只有 deploy-platform.mjs 用,注入 dispatcher否

後端 — 環境宣告與服務帳號

閘道不再從 EDGE_WORKERS_CLOUDFLARE_DISPATCH_NAMESPACE 推導預期的 dispatcher,而是使用 API 自己的環境宣告:APP_ENV(否則 ENVIRONMENT),去除前後空白並轉小寫 — staging 選 staging dispatcher,prod 或 production 選 production dispatcher。若 HOST(否則 PUBLIC_HOST)是 TeamSync 代管的 API hostname 之一,它就暗示了所屬環境;同時設了 APP_ENV/ENVIRONMENT 時,兩者必須一致。互相矛盾、除 dev、development、test 之外的任何非空環境值,或完全沒有可辨識的宣告,都會讓沒有預期的 dispatcher:EDGE_WORKERS_DISPATCH_ORIGIN 隨即驗證失敗,所有閘道呼叫都以 Edge Worker dispatcher is not configured 失敗。

變數用途規則機密
APP_ENV / ENVIRONMENT預期 dispatcher 的選擇(見上)兩者皆設時以 APP_ENV 為準否
HOST / PUBLIC_HOSTHOST:生成的 API URL、EDGE_WORKERS_GATEWAY_PUBLIC_URL 的退回值,以及 Worker 的服務帳號 apiBase;PUBLIC_HOST:只在 HOST 為空時作為上述環境提示對服務帳號綁定而言,HOST 必須是單純的 HTTPS origin:scheme 為 https、有 hostname、無 userinfo、path 為空或 /、無 query、無 fragment;Worker 的 apiBase 成為 https://<netloc>。其他任何情況(包含 http://)都不會有 apiBase,每個綁定都以 503 {"code":"api_base_unconfigured","message":"This deployment's HOST is not a bare HTTPS origin"} 被拒絕。Worker 內儲存的 apiBase 只在下一次設定寫入(操作設定 PUT 或部署暫存)時更新,憑證重設不會更新否
JWT_SECRET_KEY服務帳號驗證金鑰:由它導出的 HMAC 金鑰用來驗證服務帳號儲存的憑證必須設定。未設定 → 每次憑證送達都以 503 {"code":"service_account_verifier_unavailable","message":"Service-account credentials cannot be verified by this deployment"} 失敗,且沒有任何服務帳號能登入。輪替它會使每個服務帳號憑證失效:事後要逐一重設服務帳號以送達新的憑證。見服務帳號是

後端 — 每次呼叫的上限

在每個簽章請求時讀取,鑄進調度斷言的 limits claim,dispatcher 再套用到部門 Worker。不在 example.env 內;未設定時使用預設值。調整任一項是後端設定變更加重啟 — 不需要重新部署 dispatcher。

變數預設規則機密
EDGE_WORKERS_LIMIT_CPU_MS50ASCII 數字,1–30 000否
EDGE_WORKERS_LIMIT_SUBREQUESTS500ASCII 數字,1–1 000否

不合法的值絕不會被夾住:後端拒絕簽章,所有簽章呼叫都會以無法使用的方式失敗(invoke → 503 Department Worker gateway is unavailable、存取政策/runtime config 路由 → 503,部署的就緒探測也無法成功,最終成為 uncertain worker_readiness_timeout)。公開通道不使用這兩個變數 — 它沿用下方 dispatcher 自己的 EDGE_WORKER_* 變數。地端時,edge host 忽略 CPU 上限(改用 30 秒的牆鐘預算),並在簽章通道套用 EDGE_WORKERS_LIMIT_SUBREQUESTS,且以每個 Worker 行程為單位共用額度(見地端)。

後端 — 產物儲存

專屬 bucket + 憑證對;絕不退回應用憑證或 AWS_S3_BUCKET。使用雲端 provider 時儲存體是 R2,且 S3_PROVIDER 必須恰為 r2:

變數規則機密
EDGE_WORKERS_R2_BUCKET非空否
EDGE_WORKERS_R2_ACCESS_KEY_ID / EDGE_WORKERS_R2_SECRET_ACCESS_KEY兩者都必須設定:只設一個 → “Edge Worker R2 credentials must be configured together”;皆不設 → “dedicated Edge Worker R2 credentials are not configured”是
EDGE_WORKERS_R2_ENDPOINT_URL必須恰為 https://<account_id>.r2.cloudflarestorage.com;只有當 S3_ENDPOINT_URL 正是同一 endpoint 時才可留空否

使用地端 provider 時,產物改存在 kit 自己的產物儲存體,不會讀取 EDGE_WORKERS_R2_*(見地端一節)。兩種 provider 路徑都使用每個行程一個有界的 S3 client:連線逾時 5 秒、讀取逾時 20 秒,botocore standard 重試模式、2 次重試(最多 3 次嘗試),最多快取 8 個 client。

後端 — 地端 provider

只在 EDGE_WORKERS_PROVIDER=onprem 時使用。kit 的 setup 腳本會寫入這組變數(見地端);provider 在每次部署前檢查它,不完整的設定以 edge_workers_provider_invalid 拒絕。

變數預設規則機密
EDGE_WORKERS_ONPREM_SCOPE_ID—恰為 12 個小寫 hex([0-9a-f]{12});部署範圍成為 onprem:<id>,蓋進 outbox 的 dispatch_namespace。不合法 → Edge Worker on-prem scope is invalid否
EDGE_WORKERS_ONPREM_GATEWAY_URL—一個 http origin(無 path/query/憑證),且等於 kit 固定的內部閘道位址,否則 <NAME> must use the kit's internal service否
EDGE_WORKERS_PUBLIC_BASE_URL—HTTPS、有 hostname、無憑證/query/fragment、path 為 /edge(允許結尾的 /),否則 EDGE_WORKERS_PUBLIC_BASE_URL must be an HTTPS /edge base;Worker 的公開 URL 是 <base>/public/<script_name>否
EDGE_WORKERS_ARTIFACTS_ENDPOINT_URL—等於 kit 固定的內部產物儲存位址的 http origin否
EDGE_WORKERS_ARTIFACTS_BUCKET—非空否
EDGE_WORKERS_ARTIFACTS_ACCESS_KEY_ID / EDGE_WORKERS_ARTIFACTS_SECRET_ACCESS_KEY—兩者皆非空是
EDGE_WORKERS_HOST_AUDIENCEteamsync-edge-host後端送給 edge host 的短效(30 秒)EdDSA JWT 的 aud;以上述調度金鑰對簽發否
EDGE_BACKUP_FENCE_MAX7200ASCII 數字,1–86 400 秒:備份啟用圍欄最長可持續多久(EDGE_BACKUP_FENCE_MAX must be 1..86400 seconds)否

EDGE_WORKERS_DISPATCH_PRIVATE_KEY 與 EDGE_WORKERS_DISPATCH_KEY_ID 也必須非空。任何違規都會丟出 edge_workers_provider_invalid:origin 格式錯誤時訊息為 <NAME> must be a http origin,缺少金鑰、金鑰 id、bucket 或產物憑證時則為 Edge Worker on-prem credentials are incomplete。

setup 腳本也會寫入 EDGE_WORKERS_CONTROL_SUBNET、EDGE_WORKERS_CONTROL_RELAY_IP 與 EDGE_WORKERS_CONTROL_HOST_IP,也就是 kit 給 edge host 用的內部控制網路。只有 kit 的 setup 腳本與 compose 檔使用它們,後端不讀取(見地端)。

後端 — builder 與 starters

⚠️ 三個變數用單數 EDGE_WORKER_ 前綴;後端讀取的 EDGE_WORKERS_* 名稱用複數。已知踩雷點 — 排查「builder unavailable」前先檢查拼字。

變數預設
EDGE_WORKER_NODE_BINARY/usr/local/bin/node
EDGE_WORKER_BUILD_CLI/opt/teamsync/edge-worker-builder/scripts/build.mjs
EDGE_WORKER_STARTERS_DIR/opt/teamsync/edge-worker-starters

EDGE_WORKER_STARTERS_DIR 是 API 提供的 starter 目錄與 CLI tarball 的根目錄(見Starters 與原始碼);行程啟動時只讀取一次。

另外:EDGE_WORKERS_CLOUDFLARE_ACCOUNT_ID 在 Cloudflare client 驗證為大小寫混合 hex,但 R2 endpoint 檢查只收小寫 — 大寫值會過一邊、掛另一邊。請用小寫。

builder 子行程收到的是六變數乾淨環境(LANG、LC_ALL、NODE_ENV=production、PATH、SOURCE_DATE_EPOCH=0、TZ=UTC)— 憑證永遠到不了它。

Dispatcher(Cloudflare Worker 變數,由 deploy-platform.mjs 設定)

變數值
EDGE_WORKER_ASSERTION_PUBLIC_JWKEd25519 公開 JWK(repo 設定檔放的是哨兵值 DEPLOY_VIA_SCRIPTS_DEPLOY_PLATFORM_MJS — 手動 wrangler deploy 產出的 dispatcher 會對一切回 503)
EDGE_WORKER_ASSERTION_ISSUER / EDGE_WORKER_ASSERTION_AUDIENCEteamsync-backend / teamsync-department-workers
EDGE_WORKER_CPU_MS / EDGE_WORKER_SUBREQUESTS每次呼叫的限制,wrangler.jsonc(頂層、staging、production)皆為 50 / 500;套用於公開通道,以及斷言沒帶 limits claim 的簽章請求(解析圍欄:1–30 000/1–1 000;無效 → 只有這些請求回 503 dispatcher_unavailable)。與後端的 EDGE_WORKERS_LIMIT_* 一起構成部門 Worker 對外流量的唯一界限 — 沒有 Outbound Worker 或 egress 允許清單變數
EDGE_WORKER_SERVING_ROUTESJSON 物件,把 Worker 的 script 名稱對映到它的服務位置與路由 epoch;wrangler.jsonc 在兩個環境皆為 {}(缺省也視為 {});值不合法 → 每個請求都回 503 dispatcher_unavailable。由 deploy-platform.mjs 從下方的選用輸入 EDGE_WORKERS_SERVING_ROUTES 寫入,該輸入未設定時則沿用線上 dispatcher 目前的值。後端從不讀取這兩個名稱
EDGE_DISPATCHER_SOURCE_DIGESTdispatcher 原始碼(src/dispatcher.ts、wrangler.jsonc、package-lock.json)的 sha256,每次部署以純文字變數蓋章;deploy-platform.mjs --drift 拿它與 checkout 比對。dispatcher 程式碼不讀取

Transport/背景 worker 相關(共用基礎設施)

變數預設備註
DEFAULT_BACKGROUND_WORKER_TYPElegacy(GCP 上為 pubsub)legacy | batch | sqs | pubsub;決定部署任務的 transport
PUBSUB_BACKGROUND_TASK_TOPIC / PUBSUB_SUBSCRIPTIONteamsync-background-tasks / …-sub部署任務走批次 topic
PUBSUB_MAX_LEASE_SECONDS / PUBSUB_DRAIN_TIMEOUT_SECONDS3300 / 3300consumer 租約 + SIGTERM 排空
PUBSUB_SELF_GATED_TASK_FUNCSsrc.tasks.notification_task.deliver:delivery_id部署任務是內建的 self-gated 項目,環境變數蓋不掉
GOOGLE_CLOUD_PROJECT / GCP_PROJECT、REDIS_HOST、REDIS_PORT、REDIS_USE_TLS、REDIS_USE_CLUSTER_MODE、REDIS_PASSWORD—consumer 前置需求
AWS_BATCH_JOB_ID、AWS_BATCH_JOB_ATTEMPT、JOB_ID—驅動 Batch 第 2 次嘗試的租約回收規則

沒有任何環境變數控制這些程式碼常數:60 秒回收迴圈、三個批次上限(50)、租約 TTL 與退避階梯(見背景任務);以及 15 秒 host 調解(退役)迴圈、它的 20 秒單輪逾時、10 秒開始預算、每個 pod 每輪 3 次 Cloudflare 退役、8 秒鎖定預算、300 秒卡住門檻與 15 分鐘上傳寬限(見退役)。

平台佈建(僅 deploy-platform.mjs)

需要(Infisical 範圍):EDGE_WORKERS_CLOUDFLARE_API_TOKEN、…_ACCOUNT_ID、…_DISPATCH_NAMESPACE(必須是該環境的 dispatch namespace 之一)、…_WORKERS_SUBDOMAIN、…_DISPATCH_KEY_ID、…_DISPATCH_ISSUER、…_DISPATCH_AUDIENCE、…_DISPATCH_PUBLIC_JWK、…_DISPATCH_PRIVATE_KEY、…_DISPATCH_ORIGIN,以及 staging 與 production 的 dispatcher 還需要 EDGE_WORKERS_R2_BUCKET(後端已在使用的 edge 產物 bucket)。選用:EDGE_WORKERS_SERVING_ROUTES — 最多 32 768 字元、128 個項目的 JSON 物件字串,key 為 ^dw-[0-9a-f]{48}$,每個值恰為 {dispatch_namespace, routing_epoch},namespace 須為已知的 binding、routing_epoch 為 ≥ 1 的安全整數,否則 serving routes configuration is invalid;它會寫入 dispatcher 變數 EDGE_WORKER_SERVING_ROUTES,未設定時,例行執行會讀取線上 dispatcher 並保留它目前的值。對照表中的項目優先於後端在搬移 Worker 時所記錄的啟用。任何符合 REPLACE_WITH_ENV_ / CHANGE_ME / DEPLOY_VIA_SCRIPT_ONLY 的值都被拒絕;私鑰必須能推導出完全一致的公開 JWK。--drift 只需要 …_API_TOKEN 與 …_ACCOUNT_ID。在 CI 中,這些值經由 GitHub OIDC 從 Infisical 取得 — GitHub 內不存放任何長期機密。細節:平台佈建。

Last updated on