CI/CD 與發佈策略
第 38 章的結論是「綠燈的測試不保證能部署」,第 39 章的結論是「未捕捉的例外在 trace 裡是 ok」。這一章把這兩件事變成一條真的能擋住問題的 pipeline。
40.1 先分清楚 version 與 deployment
Section titled “40.1 先分清楚 version 與 deployment”這是整章的地基:
| 是什麼 | 指令 | |
|---|---|---|
| version | 一份「已上傳但不一定在跑」的程式碼 + 設定 | wrangler versions upload |
| deployment | 「現在哪個(或哪些)version 在接流量」 | wrangler versions deploy |
| 兩件事一起做 | wrangler deploy |
這個拆分就是漸進式發佈與快速回滾的全部基礎。 一旦你習慣「上傳」與「切流量」是兩件事,pipeline 的形狀就自然出來了。
三個實測到的硬限制:
- 第一次建立 Worker 不能用
versions upload,會失敗。要先wrangler deploy(或 C3)。 versions upload不支援 Service Worker 語法,必須是 ES modules。- 只有最近 100 個 version 能拿來做 deployment 或 rollback。
40.2 Workers Builds vs GitHub Actions
Section titled “40.2 Workers Builds vs GitHub Actions”Cloudflare 自己的 CI 叫 Workers Builds(接 GitHub / GitLab,push 就跑)。
實測到的額度(官方 limits 頁):
| Free | Paid | |
|---|---|---|
| build 分鐘數 | 3,000 / 月 | 6,000 / 月(超出 $0.005/min) |
| 併發 build | 1 | 6 |
| build timeout | 20 分鐘 | 20 分鐘 |
| CPU / RAM / 磁碟 | 2 vCPU / 8 GB / 20 GB | 4 vCPU / 8 GB / 20 GB |
| 環境變數 | 64 個,每個 5 KB | 同左 |
⚠️ 不要說 Workers Builds 已經 GA。 文件上沒有 beta 標籤,但我也找不到 GA 公告。準確的說法是:文件不再標它 beta。
它的幾個關鍵行為:
- dashboard 上的 Worker 名稱必須和指定根目錄的 wrangler 設定裡的
name一致,否則 build 失敗。 - build 成功會存成一個 version;deploy command 設成
wrangler deploy就會自動升成 Active Deployment,設成npx wrangler versions upload就只存不發。這是關掉自動部署的官方做法。 - 不支援自架的 GitHub / GitLab,也不支援其他 Git 服務。
- 非 production 分支的 build 預設是關的,要手動開「non-production branch builds」才會有 preview URL 與 PR 留言。
- 注入的 build 變數:
CI、WORKERS_CI、WORKERS_CI_BUILD_UUID、WORKERS_CI_COMMIT_SHA、WORKERS_CI_BRANCH—— runtime 拿不到。
monorepo:build watch paths 的兩個 bypass
Section titled “monorepo:build watch paths 的兩個 bypass”第 26 章那個 pnpm workspace 在這裡要設兩層:每個 Worker 各自的 root directory,加上 build watch paths。
預設是 includes ["*"]、excludes [],判斷順序是「先排除、再包含、有中就 build」。但有兩個會直接跳過整個路徑比對的情況:
“A push event contains 0 file changes… A push event contains 3000+ file changes or 20+ commits”
一次 merge 20 個 commit 進來,你所有的 Worker 都會重新 build。 大型 monorepo 要把這個算進 build 分鐘數。
什麼時候選 GitHub Actions
Section titled “什麼時候選 GitHub Actions”需要下面任何一項時:多階段的 gate(staging → 人工核可 → production)、漸進式流量切換、跟既有的 CI 共用 cache / matrix、fork PR 的無憑證檢查。本章的範例走這條路。
40.3 cloudflare/wrangler-action@v4
Section titled “40.3 cloudflare/wrangler-action@v4”實測最新版 v4.0.0(tag v4 / v4.0 / v4.0.0 都指向同一個 commit,commit 日期 2026-05-12)。
⚠️ GitHub releases 頁面在我抓取時把日期渲染成 2024 年。以 git object 的日期為準。
v4 唯一的破壞性變更(CHANGELOG 4.0.0):預設安裝的 wrangler 從 v3 換成 v4。要留在 v3 就明寫 wranglerVersion: "3.90.0"。
v3 那批仍然有效的破壞性變更:不再支援 wrangler v1、不再支援 Global API key + Email 認證、action 版本必須帶 v 前綴(@v4 可以,@4.x.x 不行)。
action.yml 實測的完整 input:
apiToken, accountId, quiet, environment, workingDirectory, wranglerVersion,secrets, preCommands, postCommands, command, vars, packageManager, gitHubTokenoutput:command-output、command-stderr、deployment-url、pages-deployment-alias-url、pages-deployment-id、pages-environment。runtime 是 node24。
🔴
vars這個 input 存在於action.yml,但 README 完全沒寫。 它和secrets一樣是換行分隔的環境變數名稱清單,差別是綁成 var 而不是 secret。又一次 schema 比文件寬。
secrets 的行為值得抄一遍原文:
“A string of environment variable names, separated by newlines. These will be bound to your Worker as Secrets and must match the names of environment variables declared in
envof this workflow.”
也就是說 secret 名稱要在兩個地方各寫一次(with.secrets 列名字,env 給值)。3.14.1 起底層改用 secret bulk。
40.4 secrets 在 CI 裡的三條路
Section titled “40.4 secrets 在 CI 裡的三條路”| 方式 | 上限 | 刪除 | 適合 |
|---|---|---|---|
wrangler secret bulk [file] | 一次 100 個 | JSON 裡把值設成 null 可刪;.env 格式不能刪 | 一般情況 |
versions upload --secrets-file | 同上 | 不能刪,「Applies additively… omitted secrets will not be deleted」 | 和 version 綁在一起上傳 |
| Secrets Store(帳號層) | 每帳號 100 個 secret、只能有一個 store、單一 secret ≤ 1024 bytes | dashboard / API | 跨 Worker 共用 |
🔴
--secrets-file是「加法」,不是「同步」。 你從檔案裡刪掉一個 key,線上那個 secret 不會被刪。想清空得另外wrangler secret delete。同理,
--keep-vars的說明也很值得看清楚:預設情況下 wrangler 會先刪掉所有 var 再套用設定檔裡的,但**「secrets are never deleted by deployments」**。var 和 secret 的生命週期完全不同。
Secrets Store(open beta)的 binding 長這樣:
{ "secrets_store_secrets": [ { "binding": "MY_SECRET", "store_id": "<STORE_ID>", "secret_name": "<NAME>" } ]}存取是非同步的:const key = await env.MY_SECRET.get();(和 env.FOO 直接讀不一樣,第 4 章的直覺在這裡不適用)。
⚠️ 本機開發拿不到 production 的 Secrets Store secret(dashboard / API /
--remote建的那些)。又一條進第 38 章那張表。另外 Secrets Store 沒有 limits 頁,上面那些數字是從 manage-secrets 頁面掃出來的,引用前自己再確認一次。
40.5 漸進式發佈:真正要小心的是 Durable Object
Section titled “40.5 漸進式發佈:真正要小心的是 Durable Object”wrangler versions upload --tag "$GITHUB_SHA" --message "..."wrangler versions deploy --version-tag "$GITHUB_SHA@10" --yes # 10% 流量# 觀察…wrangler versions deploy --version-tag "$GITHUB_SHA@100" --yes # 全量💡 用
--version-tag而不是去 stdout 裡剪 version id。--version-tag支援和 version id 一樣的<tag>@<percentage>簡寫,把$GITHUB_SHA當 tag 上傳,pipeline 就不需要解析輸出。
🔴 一次最多兩個 version
Section titled “🔴 一次最多兩個 version”官方文件沒有明說這個數字。wrangler 的原始碼有:
"max-versions": { hidden: true, // experimental, not supported long-term describe: "Maximum allowed versions to select", type: "number", default: 2 // (when server-side limitation is lifted, we can update this default or just remove the option entirely)}錯誤訊息是 Too many versions selected. You can deploy at most 2 version(s) at a time. —— 這是伺服器端的限制,那個 flag 是隱藏的、標記為 experimental。不要設計三段式金絲雀。
百分比的精細度沒有文件。wrangler 客戶端用 parseFloat 收,只驗 0–100 與加總,小數是收得下的;伺服器端怎樣我無法驗證。不要宣稱可以用小數。
Durable Object:每個實例被釘在一個 version 上
Section titled “Durable Object:每個實例被釘在一個 version 上”這是漸進式發佈最反直覺的部分,官方原文:
“To provide global uniqueness, only one version of each Durable Object can run at a time.”
“When you create a new gradual deployment for a Worker with Durable Objects, each Durable Object is assigned a Worker version based on the percentages you configured in your deployment. This version will not change until you create a new deployment.”
三個保證:
- 同一個 deployment 期間,打到某個 DO 的請求永遠走同一個 version。
- 只要你用相同順序列出 version 並且只調高百分比,原本被分到那個 version 的 DO 不會被換回去。
- DO 只在被分到不同 version 時才會 reset,所以照上面做的話每個 DO 最多只被 reset 一次。
還有兩條硬規則:
- 一個 bundle 通常同時定義 DO class 和使用它的 Worker,所以你沒辦法把兩者分開部署。
- 🔴 改動 DO class 生命週期的 version 根本不能用
versions upload上傳(exports宣告式或舊的migrations陣列都算)。官方說法是「Durable Object lifecycle changes are atomic operations」,而且一旦部署,就再也不能回滾到那個變更之前的任何 version。
實務規則:任何 create / delete / rename / transfer DO class 的變更,必須用
wrangler deploy單獨發一次,不要和其他程式碼變更混在一起。 第 14–17 章那些 DO 設計決定,在這裡變成部署流程的約束。
Workers with Assets:會 404
Section titled “Workers with Assets:會 404”官方明文警告:
“If a user’s initial request for
/goes to Version A, they’ll receive HTML that referencesindex-a1b2c3d4.js. However, when their browser then requests/assets/index-a1b2c3d4.js, that request might be routed to Version B, which only containsindex-m3n4o5p6.js, resulting in a 404 error.”
解法是 version affinity:用 Transform Rule 設 Cloudflare-Workers-Version-Key header。
⚠️ Transform Rules 需要你自己的 zone 上的 route,
*.workers.dev上沒有。 而且「The platform hashes the key… you do not choose which version a key maps to」—— 你只能保證同一個 key 一致,不能指定它去哪個 version。
第 24、25 章那些 React Router / Astro 的部署,如果要漸進式發佈就必須先有自訂網域。
查不到的東西
Section titled “查不到的東西”Queue consumer 在漸進式發佈期間走哪個 version,官方文件完全沒寫。 Cron Triggers 與 Tail Workers 也沒寫。第 19、20 章的東西在這裡是空白 —— 不要猜,設計上就避免在漸進式發佈期間依賴 consumer 的版本一致性。
Pages 的漸進式發佈也沒有文件(Pages 有自己的 preview deployment 模型)。這是「沒寫」,不是「不支援」。
40.6 Rollback 的三個限制
Section titled “40.6 Rollback 的三個限制”wrangler rollback [version-id] --message "reason" --yes不給 version id 就回到「目前這個的前一個」。
官方原文最重要的一句:
“Resources connected to your Worker will not be changed during a rollback.” “Errors could occur if using code for a prior version if the structure of data has changed…”
回滾只換程式碼,不換資料。 你的 D1 schema、KV 裡的資料格式、DO storage 的形狀都會留在新的樣子。這代表 migration 必須是向後相容的 —— 第 12 章那個 D1 migration 的紀律在這裡收成。
三個會讓 rollback 直接被擋下來的情況:
- 只能回到最近 100 個 version。
- 兩個 version 之間發生過 Durable Object migration。
- 目標 version 綁著一個已經不存在的 R2 bucket / KV namespace / queue。
如果目前是兩個 version 的分流,rollback 會把它換成單一 version 的 deployment 並把 100% 流量導過去。
40.7 Preview URLs
Section titled “40.7 Preview URLs”兩種:versioned(每個 version 自動有,需要 wrangler ≥ 3.74.0)與 aliased(--preview-alias,需要 wrangler ≥ 4.21.0)。
格式:
<VERSION_PREFIX 或 ALIAS>-<WORKER_NAME>.<SUBDOMAIN>.workers.devwrangler versions upload --preview-alias pr-123# → https://pr-123-my-worker.<subdomain>.workers.dev規則(實測官方原文):
- alias 只能在 upload 當下建立,事後不能加。
- 只能小寫字母、數字、dash;必須以小寫字母開頭。
- alias + Worker 名稱(含中間的 dash)不能超過 63 字元(DNS label 限制)。
- 只保留最近部署的 1000 個 alias,超過會刪掉最久沒用的。
開關:
{ "workers_dev": true, "preview_urls": true }preview_urls預設跟著workers_dev。- ⚠️ dashboard 上的切換會被下一次
wrangler deploy覆蓋掉(如果設定檔不一致)。寫進 repo。
四個限制,其中兩個很痛:
- 🔴 實作了 Durable Object 的 Worker 不會產生 preview URL。
- 🔴 preview URL 看不到任何 log —— Workers Logs、
wrangler tail、Logpush 全部沒有。第 39 章那一整套在這裡是關的。 - Workers for Platforms 的 user Worker 目前也沒有(官方說是暫時的)。
- 不能換成
workers.dev以外的網域。
所以第 14–17 章那些用 DO 的東西,PR preview 這條路走不通,只能靠 staging 環境。
40.8 🔴 versions upload 不會套用 observability 設定
Section titled “40.8 🔴 versions upload 不會套用 observability 設定”這一條在官方文件裡完全沒有,是我從 wrangler 的 bundle 裡讀出來的:
async function maybePatchSettings(config, accountId, workerName) { const maybeUndefinedSettings = { logpush: config.logpush, tail_consumers: config.tail_consumers, streaming_tail_consumers: config.streaming_tail_consumers, observability: config.observability // TODO reconcile with how regular deploy handles empty state }; // … log("No non-versioned settings to sync. Skipping..."); // … "Syncing non-versioned settings" / "Synced non-versioned settings:"}這四個是「非版本化設定」(non-versioned settings),在 versions deploy 的時候同步,不是跟著 version 走。
實務後果很直接:
你改了
observability然後只跑versions upload,設定不會生效。 要等到真的有一次 deployment。第 39 章那個「traces 抽樣率」的調整,在只上傳不部署的流程裡是靜默無效的。
(順帶一提,streaming_tail_consumers 又出現了 —— 第 39 章說過它在 schema 裡但文件查不到,這裡是第二個證據。)
40.9 --strict:把「安靜覆蓋」變成「失敗」
Section titled “40.9 --strict:把「安靜覆蓋」變成「失敗」”wrangler deploy 與 wrangler versions upload 都有 --strict,但同一頁上的說明不一樣:
deploy:“the command will be more defensive and prevent deployments which could introduce potential issues. In particular, this mode prevents deployments if the deployment would potentially override remote settings in non-interactive environments.”
versions upload:“Enables strict mode, which prevents uploads when there are conflicting remote changes.”
兩邊都沒有明確定義什麼算「conflicting remote change」。機制在 2025-11-21 的 changelog:wrangler deploy 會先顯示本地設定與 dashboard 設定的差異、詢問要不要更新本地設定檔,純新增的變更則不詢問直接放行。需要 wrangler ≥ 4.50.0。
CI 裡沒有互動介面,所以沒有提示,只會安靜覆蓋。--strict 就是把那個安靜覆蓋變成 build 失敗。(這句因果是我的推論,文件沒有這樣寫,但這是它唯一合理的用途。)
40.10 完整的 pipeline
Section titled “40.10 完整的 pipeline”範例的 .github/workflows/deploy.yml 分成四個 job。
1. check —— 不需要憑證,fork PR 也能跑
Section titled “1. check —— 不需要憑證,fork PR 也能跑”- name: types are in sync with wrangler.jsonc run: npx wrangler types --check- run: npx tsc --noEmit- run: npm test --if-present- name: bundle budget run: node scripts/bundle-budget.mjs --limit-kb 900wrangler types --check 實測行為:設定檔改了但沒重新產生型別 → exit 1;重新產生後 → exit 0。
⚠️ 不要 pipe 它。
npx wrangler types --check | tail -5會讓$?變成tail的結果,永遠是 0。我第一次量的時候就踩到了。
bundle budget 用的是 wrangler deploy --dry-run --outdir dist:不需要 API token,但會讀設定檔,所以壞掉的 wrangler.jsonc 在這一步就會失敗。範例的腳本量的是 gzip 後的大小 —— 平台限制是壓縮後的。
2. preview —— 只上傳,不部署
Section titled “2. preview —— 只上傳,不部署”command: >- versions upload --preview-alias pr-${{ github.event.number }} --tag ${{ github.sha }}然後對 pr-<n>-<worker>.<subdomain>.workers.dev 跑 smoke,再把網址貼回 PR。
3. staging —— 部署 + smoke
Section titled “3. staging —— 部署 + smoke”command: deploy --strictsecrets: | SESSION_SECRET UPSTREAM_TOKENenv: SESSION_SECRET: ${{ secrets.SESSION_SECRET }} UPSTREAM_TOKEN: ${{ secrets.UPSTREAM_TOKEN }}4. production —— upload → 10% → soak → smoke → 100%
Section titled “4. production —— upload → 10% → soak → smoke → 100%”用 GitHub 的 environment: production 加 required reviewer,就有了人工核可 gate,不需要額外工具。
concurrency 不是可選的
Section titled “concurrency 不是可選的”concurrency: group: deploy-${{ github.ref }} cancel-in-progress: true沒有這個,兩次 push 會賽跑,舊的 build 可能後到而覆蓋新的。
rollback 要做成按鈕
Section titled “rollback 要做成按鈕”.github/workflows/rollback.yml 用 workflow_dispatch,輸入 version id(可留空)與原因。
凌晨三點你不會記得指令。 把 rollback 做成一個按鈕,並且回滾之後也跑一次 smoke。
40.11 smoke test 要驗什麼
Section titled “40.11 smoke test 要驗什麼”範例的 scripts/smoke.mjs 有三個設計取自前兩章的實測:
1. 指數退避重試。 新部署要幾秒才會回應,但要有上限(範例是 6 次)。
2. 斷言 status code,不要斷言 outcome。 第 39 章實測未捕捉例外在 trace 裡是 outcome: "ok":
check("GET / is not a 5xx", root.status < 500, `got ${root.status}`);3. 用 version_metadata 分辨自己打到哪一半。
{ "version_metadata": { "binding": "CF_VERSION_METADATA" } }if (url.pathname === "/__health") { return Response.json({ ok: true, env: env.BUILD_ENV, version: env.CF_VERSION_METADATA });}本機實測回傳:
{"ok":true,"env":"local","version":{"id":"0653ce41-…","tag":"","timestamp":"2026-08-01T10:04:35.711Z"}}沒有這個 binding,漸進式發佈期間你的 smoke test 無法知道自己打到 10% 還是 90% 那一邊 —— 它可能連續六次都打到舊版本然後回報「一切正常」。
40.12 🔴 wrangler types 會告訴你哪個 environment 少了 binding
Section titled “40.12 🔴 wrangler types 會告訴你哪個 environment 少了 binding”這是意外量到的,但對 CI 很有用。
範例一開始只在頂層宣告 version_metadata,named environment 沒宣告。產生的型別:
interface __BaseEnv_Env { BUILD_ENV: "staging" | "production" | "local"; CF_VERSION_METADATA?: WorkerVersionMetadata; // ← 注意這個問號}declare namespace Cloudflare { interface StagingEnv { BUILD_ENV: "staging"; } // ← 完全沒有這個 binding interface ProductionEnv { BUILD_ENV: "production"; }}只加到 staging:
interface __BaseEnv_Env { CF_VERSION_METADATA?: WorkerVersionMetadata; // ← 還是問號}interface StagingEnv { CF_VERSION_METADATA: WorkerVersionMetadata; ... } // ← 這裡是必要的interface ProductionEnv { BUILD_ENV: "production"; } // ← 還是沒有兩個都加之後,問號才消失。
規則:wrangler types 對所有 environment 取聯集,只要有任何一個 environment 缺這個 binding,base Env 裡它就是 optional。
這正是第 26 章那個「named environment 不會繼承頂層設定」的型別化版本(wrangler schema 對 tail_consumers 也明寫了同一件事:「This field is not automatically inherited from the top level environment, and so must be specified in every named environment」)。
CI 的用法:那個
?就是你的警報。 搭配strict模式,忘了在 production 宣告 binding 會在tsc --noEmit就爆掉,而不是部署之後才發現env.FOO是 undefined。
40.13 本章實測結論彙整
Section titled “40.13 本章實測結論彙整”| # | 結論 | 影響 |
|---|---|---|
| 1 | version(上傳)與 deployment(切流量)是兩件事 | 漸進式發佈與回滾的基礎 |
| 2 | 第一次建立 Worker 不能用 versions upload;也不支援 Service Worker 語法 | 要先 wrangler deploy |
| 3 | 只有最近 100 個 version 可用於 deployment / rollback | |
| 4 | Workers Builds:Free 3,000 / Paid 6,000 build 分鐘;併發 1 / 6;timeout 20 分 | |
| 5 | 不要說 Workers Builds 已 GA —— 沒有 beta 標籤,也沒有 GA 公告 | |
| 6 | deploy command 設 wrangler versions upload 就是官方的「只 build 不部署」 | |
| 7 | 🔴 build watch paths 有兩個 bypass:0 個檔案變更,或 3000+ 檔案 / 20+ commit | 大 merge 會 build 全部 Worker |
| 8 | build 變數(WORKERS_CI_*)runtime 拿不到 | |
| 9 | wrangler-action 最新 v4.0.0,commit 日期 2026-05-12(GitHub 頁面渲染的 2024 是錯的) | |
| 10 | v4 唯一破壞性變更:預設 wrangler 從 v3 換成 v4 | 要留 v3 就 wranglerVersion: "3.90.0" |
| 11 | action 版本必須帶 v 前綴(@v4 ✅,@4.x.x ❌) | v3 起的規則 |
| 12 | 🔴 vars input 存在於 action.yml,README 沒寫 | 又一次實作比文件寬 |
| 13 | 🔴 --secrets-file 是加法:「omitted secrets will not be deleted」 | 刪 secret 要另外下指令 |
| 14 | secret bulk 一次 100 個;JSON 設 null 可刪,.env 格式不能刪 | |
| 15 | --keep-vars 說明:預設會先刪光 var 再套用;但 secret 永遠不會被 deployment 刪掉 | var 與 secret 生命週期不同 |
| 16 | Secrets Store open beta;每帳號 100 個 secret、只能一個 store、單一 secret ≤ 1024 bytes | 沒有 limits 頁,數字要自己再確認 |
| 17 | Secrets Store 的存取是非同步:await env.X.get() | 和一般 binding 不同 |
| 18 | 本機拿不到 production 的 Secrets Store secret | 進第 38 章那張表 |
| 19 | 🔴 一次最多 2 個 version(wrangler 原始碼 max-versions default 2,hidden、experimental) | 不要設計三段式金絲雀 |
| 20 | 百分比精細度無文件;wrangler 客戶端用 parseFloat 收 | 不要宣稱可用小數 |
| 21 | 用 --version-tag <tag>@<pct>,不要去 stdout 剪 version id | 支援和 id 一樣的簡寫 |
| 22 | DO 在整個 deployment 期間被釘在同一個 version,只在被換 version 時 reset | 照相同順序、只調高百分比 → 每個 DO 最多 reset 一次 |
| 23 | 🔴 改 DO class 生命週期的 version 根本不能 versions upload,而且一旦部署就再也回不去 | 單獨發一次,不要混其他變更 |
| 24 | Workers with Assets 漸進式發佈會因為 asset 名稱不匹配而 404 | 要用 version affinity |
| 25 | 🔴 version affinity 靠 Transform Rule,*.workers.dev 上沒有 | 要漸進式發佈就得先有自訂網域 |
| 26 | Queue consumer / Cron / Tail Worker 在漸進式發佈期間的行為,官方完全沒寫 | 不要猜,設計上避開 |
| 27 | Pages 的漸進式發佈沒有文件 | 是「沒寫」不是「不支援」 |
| 28 | 回滾只換程式碼,不換資料 | migration 必須向後相容(第 12 章) |
| 29 | rollback 被擋的三種情況:超過 100 個 version、期間有 DO migration、綁的 R2/KV/queue 已不存在 | |
| 30 | preview alias 只能在 upload 當下建立;限小寫字母開頭;alias+name ≤ 63 字元;只留最近 1000 個 | |
| 31 | preview_urls 預設跟著 workers_dev;dashboard 的切換會被下次 deploy 覆蓋 | 寫進 repo |
| 32 | 🔴 用了 Durable Object 的 Worker 不會有 preview URL | 第 14-17 章的東西沒有 PR preview |
| 33 | 🔴 preview URL 完全沒有 log(Workers Logs / wrangler tail / Logpush 都沒有) | 第 39 章那套在這裡是關的 |
| 34 | 🔴 logpush / tail_consumers / streaming_tail_consumers / observability 是「非版本化設定」,在 versions deploy 時才同步 | 只 upload 不 deploy,observability 改動不會生效(官方文件沒有這條) |
| 35 | --strict 在 deploy 與 versions upload 的說明同頁不同字;需要 wrangler ≥ 4.50.0 | 用途是把 CI 裡的安靜覆蓋變成失敗 |
| 36 | wrangler types --check:設定改了未重產 → exit 1;重產後 → exit 0 | ⚠️ 不要 pipe,會吃掉 exit code |
| 37 | wrangler deploy --dry-run --outdir 不需要 API token,但會驗設定檔 | fork PR 也能跑 bundle budget |
| 38 | 🔴 wrangler types 對所有 environment 取聯集:任一 environment 缺 binding,base Env 裡它就是 optional(?) | 那個問號就是「你忘了在某個 env 宣告」的警報 |
| 39 | version_metadata binding 本機可用,回 { id, tag, timestamp }(本機 tag 是空字串) | 沒有它,smoke test 分不出漸進式發佈的兩邊 |
40.14 動手練習
Section titled “40.14 動手練習”- 改一下
wrangler.jsonc但不重新產生型別,跑npx wrangler types --check看 exit code。然後在後面接| tail -3再跑一次,確認 exit code 變成 0 —— 這就是為什麼 CI 裡不能 pipe。 - 把一個 binding 只加到
env.staging,看worker-configuration.d.ts裡 baseEnv的那個?,再加到 production 看它消失。 - 用
wrangler versions deploy a@33 b@33 c@34觸發Too many versions selected,記下完整訊息。 - 在一個有 Durable Object 的 Worker 上跑
versions upload,確認沒有 preview URL。 - 只改
observability.head_sampling_rate然後跑versions upload,用wrangler versions view確認設定沒有跟著走;再versions deploy一次,看Syncing non-versioned settings。 - 把
scripts/smoke.mjs的重試上限拿掉,想想它在一次壞掉的部署上會卡多久。
- Workers CI/CD · Workers Builds · Limits and pricing · Build watch paths · Advanced setups
- Gradual deployments · With Durable Objects · Version affinity · Rollbacks · Preview URLs
- Gradual rollouts with assets · Wrangler commands · Secrets · Secrets Store
cloudflare/wrangler-action(版本與 input 取自 repo 的action.yml、README.md、CHANGELOG.md與 git tag)- CLI 行為與原始碼來源:
node_modules/wrangler@4.118.0(wrangler versions/deploy/rollback/types/secret --help、wrangler-dist/cli.js的max-versions與maybePatchSettings、config-schema.json) - 所有 exit code、型別產生結果與
version_metadata回傳值取自examples/ch40-cicd,2026-08-01
下一章:第 41 章 安全性與多租戶隔離 —— 把第 27 章的 auth、第 33 章的沙箱、以及本章的 secret 生命週期收攏成一份可以照著檢查的清單。