背景工作與統計
檢查 Queue、Reaction、Cron 和造訪統計的執行流程,區分訊息投遞成功與業務完成。
背景工作出問題時,通常會出現「請求成功了,結果卻沒有出現」的情況。先確認工作屬於哪個佇列,再追蹤執行紀錄。不能將所有背景工作都視為同一種訊息處理。
一、找出負責這項工作的佇列
| Binding | 名稱變數 | 目前用途 |
|---|---|---|
ASYNC_POLICY_TASK_QUEUE | ASYNC_POLICY_TASK_QUEUE_NAME | 執行 Reaction Event 的非同步 Command |
ASYNC_LOGGER_QUEUE | ASYNC_LOGGER_QUEUE_NAME | 非同步處理與儲存記錄 |
ANALYTICS_QUEUE | ANALYTICS_QUEUE_NAME | 處理第一方造訪統計訊息 |
src/entry/index.ts 會將收到的 Queue 名稱與這些變數精確比對,再分派給對應的取用者。
每個佇列都要檢查三處:queues.producers 的目標名稱、queues.consumers 的名稱,以及 vars 中對應的 *_QUEUE_NAME。三者必須一致。CLI 改寫專案資源名稱時,也會一併改寫相關變數。
npm run doctor 或 npm run doctor:remote 能檢查這項設定關係。不過,實際佇列是否存在、訊息是否到達,以及取用者是否發生錯誤,仍要查看 Cloudflare 佇列和 Worker 記錄。
二、有訊息,卻看不到業務結果
先依以下階段檢查:
產生業務事件 → 儲存執行紀錄 → 傳送 Queue 訊息
→ Worker 取用者分派 → 執行 Command → 儲存執行結果queue.send() 成功僅代表訊息傳送成功。訊息已確認,也不一定代表業務成功。取用者辨識出無效訊息、重試次數用盡,或需要人工核對時,可能會確認訊息並記錄警示,避免無止境地重複執行。
如果應用程式的非同步記錄本身也有問題,應同時查看 Worker 執行記錄,不要只依賴後台記錄頁面。否則,記錄佇列的故障可能連業務佇列的錯誤也一併隱藏。
三、查詢 Event 與 Command
先透過後台 Reaction 頁面或記錄定位執行 ID。也可以在業務資料庫 DB 中查詢最近的目標事件,以下以一次性付款事件為例:
SELECT id, event_type, event_version, user_id,
created_at, lease_expires_at
FROM event_execution
WHERE event_type = 'payment_succeeded'
ORDER BY created_at DESC
LIMIT 20;再使用實際執行 ID 查詢 Command:
SELECT id, command_key, command_type, mode, status,
attempt_count, max_attempts, sequence,
created_at, updated_at, completed_at
FROM command_execution
WHERE event_execution_id = 'replace_with_event_execution_id'
ORDER BY sequence;這裡的內部 Event 執行 ID 並不是 Stripe 的 evt_... ID。請勿混用兩者,也不要為了方便查詢而匯出全部 payload。
event_execution 沒有實際儲存的 status 欄位,Event 顯示的狀態是根據 Command 狀態計算而來。查詢 event_execution.status 會出現缺少欄位的錯誤。
| Command 狀態 | 含義 | 排查方向 |
|---|---|---|
pending | 尚未結束,可能正在等待執行或重試 | 佇列、租用資訊、順序和重試安排 |
succeeded | Handler 傳回成功,且結果已儲存 | 繼續檢查需要驗證的最終業務效果 |
failed | Handler 傳回業務失敗 | 搭配 result 中的錯誤碼,檢查輸入和業務條件 |
errored | Handler 擲出例外後結束 | 在受控環境檢查 last_error 與例外記錄 |
Event 不允許失敗後繼續執行時,前面的失敗可能阻止後續步驟。後面仍有 pending,不能直接解讀為 Queue 遺失訊息。
四、分清楚兩層重試
Command 有自己的 maxAttempts 和執行次數,目前定義的預設最大嘗試次數為 3。失敗後是否繼續嘗試,也與錯誤是否可重試有關。
Cloudflare Queue 有獨立的投遞次數。範本策略工作取用者的 max_retries 為 3,表示首次投遞後,最多再投遞三次。這不是 Command 的嘗試次數,也不能直接將兩者相乘,當作一定會執行的次數。
修改策略 Queue 的 max_retries 時,也要核對 consumeEventCommandBatch 的 maxRetries 參數。目前入口使用函式預設值 3,取用者用它判斷是否已到最後一次投遞。只修改 Wrangler 設定,可能造成判斷不一致。
持續提示租用忙碌
Event 透過租用機制避免多個取用者同時執行。看到 Event execution lease is busy 時,請查看目前時間、lease_expires_at 和對應執行記錄,確認是否有另一個請求仍在處理。
不要直接清空租用欄位,強制並行執行。租用持續忙碌,且訊息投遞次數用盡後,取用者會記錄警示。此時需要核對實際執行狀態,不能假設一直等待就一定會自動恢復。
Command outcome needs manual review
這項提示表示 Handler 已完成,但執行結果無法可靠地儲存。外部郵件、通知或其他操作可能已發生,繼續投遞可能重複產生效果,因此取用者會停止自動重試並發出警示。
請先到對應服務供應商或業務紀錄中確認效果,再決定如何恢復執行紀錄。不要看到資料庫仍是舊狀態,就立即重新執行。
修正後手動重試
範本提供後台 Reaction Command 重試入口。先修正驗證資訊、輸入或服務故障,核對前一次是否已產生副作用,再透過受權限保護的入口重試。
如果傳回 409,請查看具體提示。目前入口會拒絕重新執行已成功的 Command、拒絕處理仍持有有效租用的 Event,並要求先處理阻擋目前步驟的前序 Command。這些檢查應依提示處理,不要略過。
重試會進入所屬 Event 的執行流程,應檢查該 Event 的其他步驟是否也會繼續執行。不要直接將資料庫狀態改為 pending,也不要將重新投遞訊息視為對所有故障都安全的恢復方式。
五、Cron 未執行
目前排程與 src/entry/index.ts 的分派條件如下:
| Cron 運算式 | 工作 |
|---|---|
0 0 * * * | 安排到期的週期權益處理 |
0 1 * * * | 安排一般資料清理 |
30 */6 * * * | 執行統計資料保留原則 |
Cloudflare Cron 使用 UTC,排查時需要換算時間,請參閱 Cron Triggers。
入口會依運算式字串判斷要執行哪項工作。若只修改 wrangler.jsonc 的時間運算式,卻未同步修改原始碼中的分派條件,可能出現平台已觸發 Worker,但未進入預期工作分支的情況。
先檢查平台是否有觸發紀錄,再查執行記錄。週期權益和一般清理還會繼續產生背景工作,因此有 Cron 紀錄,不代表所有資料處理都已完成。沒有到期權益時,也可能不會出現預期的業務變更,應使用確實到期的測試案例驗證。
在本機開啟頁面,無法證明排程入口可用。需要另外測試 scheduled 流程,並使用隔離資料驗證會刪除紀錄的清理工作。
六、造訪統計沒有資料
依瀏覽器、收集介面、佇列、統計資料庫和報表的順序檢查:
- 是否啟用
deploy.analytics.enabled,頁面是否載入統計指令碼。 - 目前路徑是否遭排除。預設排除
/dashboard,不要藉由反覆重新整理後台頁面來驗證資料收集。 - 瀏覽器是否啟用 Do Not Track,擴充功能或網站同意原則是否阻擋指令碼執行。
- 是否送出收集請求,主機、Endpoint 和網站識別碼是否與目前設定一致。
- 收集介面是否接受該網域、路徑和來源,記錄中是否包含篩除原因。
ANALYTICS_QUEUE是否正常取用訊息,ANALYTICS_DB是否已完成遷移。- 報表的網站、日期和篩選條件是否涵蓋本次造訪。
可以先在統計資料庫檢查事件總量,避免查詢不必要的訪客屬性:
SELECT COUNT(*) AS event_count FROM analytics_event;測試時比較操作前後的結果即可,不應為了讓報表出現數字,就直接插入偽造的造訪紀錄。
關閉第一方統計後,目前實作會確認並捨棄已在統計佇列中的訊息,不會自動保留,供日後重新啟用時使用。修改網站 ID、保留原則或收集設定前,應了解對既有資料的影響。
修正後的驗證
發起一項可關聯的新工作,檢查訊息、執行紀錄和最終結果。再驗證失敗輸入或重複訊息,確認不會重複傳送、重複計費或重複授予權益。若是統計故障,則使用一個未遭排除的頁面,完整追蹤一次資料收集。