本文檔介紹瞭如何請求異步(非 HTTPS)後台函數以在失敗時重試。
重試語義
Cloud Functions 保證對事件源發出的每個事件至少執行一次事件驅動函數。但是,默認情況下,如果函數調用因錯誤而終止,則不會再次調用該函數,並且會刪除該事件。當您在事件驅動函數上啟用重試時,Cloud Functions 將重試失敗的函數調用,直到它成功完成或重試窗口到期。對於第二代函數,重試窗口將在 24 小時後到期。對於第一代功能,它會在 7 天后過期。新創建的事件驅動函數將使用指數退避策略重試,最小退避時間為 10 秒,最大退避時間為 600 秒,即十分鐘。此策略會在您首次部署新函數時應用。它不會追溯應用於在本發行說明中描述的更改生效之前首次部署的現有功能,即使您重新部署這些功能也是如此。
如果未為某個函數啟用重試(這是默認設置),該函數始終會報告它已成功執行,並且200 OK
響應代碼可能會出現在其日誌中。即使函數遇到錯誤,也會發生這種情況。為清楚說明您的函數何時遇到錯誤,請確保適當地報告錯誤。
為什麼事件驅動函數無法完成
在極少數情況下,函數可能會由於內部錯誤而過早退出,並且默認情況下該函數可能會或可能不會自動重試。
更典型的是,事件驅動的函數可能由於函數代碼本身拋出的錯誤而無法成功完成。可能發生這種情況的一些原因如下:
- 該函數包含錯誤,運行時拋出異常。
- 該函數無法到達服務端點,或在嘗試到達端點時超時。
- 該函數有意拋出異常(例如,當參數驗證失敗時)。
- 當用 Node.js 編寫的函數返回被拒絕的承諾或將非
null
值傳遞給回調時。
在上述任何一種情況下,函數默認停止執行,事件被丟棄。如果您想在發生錯誤時重試函數,可以通過設置“失敗時重試”屬性來更改默認重試策略。這會導致事件重複重試最多多天,直到函數成功完成。
啟用和禁用重試
使用 GCP 控制台
您可以在 GCP Console 中啟用或禁用重試,如下所示:
進入雲平台控制台的雲函數概覽頁面。
單擊創建函數。或者,單擊現有函數以轉到其詳細信息頁面,然後單擊編輯。
為您的函數填寫必填字段。
確保觸發器字段設置為基於事件的觸發器類型,例如 Cloud Pub/Sub 或 Cloud Storage。
單擊更多展開高級設置。
選中或取消選中標記為Retry on failure 的框。
在函數代碼中
借助 Cloud Functions for Firebase,您可以在函數代碼中啟用重試。為後台函數執行此操作,例如functions.foo.onBar(myHandler);
,使用runWith
並配置失敗策略:
functions.runWith({failurePolicy: true}).foo.onBar(myHandler);
如圖所示設置true
配置一個函數以在失敗時重試。
最佳實踐
本節介紹使用重試的最佳實踐。
使用重試來處理暫時性錯誤
因為你的函數會不斷重試直到成功執行,所以在啟用重試之前應該通過測試從你的代碼中消除像錯誤這樣的永久性錯誤。重試最好用於處理間歇性/暫時性故障,這些故障在重試時很可能得到解決,例如不穩定的服務端點或超時。
設置結束條件以避免無限重試循環
最佳做法是在使用重試時保護您的函數免於連續循環。您可以通過在函數開始處理之前包含一個明確定義的結束條件來做到這一點。請注意,此技術僅在您的函數成功啟動並且能夠評估結束條件時才有效。
一種簡單而有效的方法是丟棄時間戳早於特定時間的事件。這有助於避免在故障持續存在或比預期持續時間更長時執行過多。
例如,此代碼片段會丟棄所有早於 10 秒的事件:
const eventAgeMs = Date.now() - Date.parse(event.timestamp);
const eventMaxAgeMs = 10000;
if (eventAgeMs > eventMaxAgeMs) {
console.log(`Dropping event ${event} with age[ms]: ${eventAgeMs}`);
callback();
return;
}
將catch
與 Promises 結合使用
如果您的函數啟用了重試,則任何未處理的錯誤都將觸發重試。確保您的代碼捕獲不應導致重試的任何錯誤。
這是您應該做什麼的示例:
return doFooAsync().catch((err) => {
if (isFatal(err)) {
console.error(`Fatal error ${err}`);
}
return Promise.reject(err);
});
使可重試的事件驅動函數冪等
可以重試的事件驅動函數必須是冪等的。以下是使此類函數冪等的一些一般準則:
- 許多外部 API(例如 Stripe)允許您提供一個冪等鍵作為參數。如果您正在使用這樣的 API,您應該使用事件 ID 作為冪等鍵。
- 冪等性適用於至少一次交付,因為它可以安全地重試。因此,編寫可靠代碼的一般最佳做法是將冪等性和重試結合起來。
- 確保您的代碼在內部是冪等的。例如:
- 確保突變可以發生不止一次而不會改變結果。
- 在改變狀態之前查詢事務中的數據庫狀態。
- 確保所有副作用本身都是冪等的。
- 獨立於代碼,在函數外強加事務檢查。例如,在某處持久化狀態記錄給定事件 ID 已被處理。
- 處理帶外的重複函數調用。例如,有一個單獨的清理進程,在重複的函數調用後進行清理。
配置重試策略
根據您的 Cloud Functions 的需要,您可能希望直接配置重試策略。這將允許您設置以下任意組合:
- 將重試窗口從 7 天縮短至 10 分鐘。
- 更改指數退避重試策略的最小和最大退避時間。
- 將重試策略更改為立即重試。
- 配置死信主題。
- 設置最大和最小投遞嘗試次數。
配置重試策略:
- 編寫 HTTP 函數。
- 使用 Pub/Sub API 創建 Pub/Sub 訂閱,將函數的 URL 指定為目標。
有關直接配置Pub/Sub 的更多信息,請參閱有關處理故障的 Pub/Sub 文檔。