Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

重試異步函數

透過集合功能整理內容 你可以依據偏好儲存及分類內容。

本文檔介紹瞭如何請求異步(非 HTTPS)後台函數以在失敗時重試。

重試語義

Cloud Functions 保證對事件源發出的每個事件至少執行一次事件驅動函數。但是,默認情況下,如果函數調用因錯誤而終止,則不會再次調用該函數,並且會刪除該事件。當您在事件驅動函數上啟用重試時,Cloud Functions 將重試失敗的函數調用,直到它成功完成或重試窗口到期(默認情況下,7 天后)。

如果未為某個函數啟用重試(這是默認設置),該函數始終會報告它已成功執行,並且200 OK響應代碼可能會出現在其日誌中。即使函數遇到錯誤,也會發生這種情況。為清楚說明您的函數何時遇到錯誤,請確保適當地報告錯誤

為什麼事件驅動函數無法完成

在極少數情況下,函數可能會由於內部錯誤而過早退出,並且默認情況下該函數可能會或可能不會自動重試。

更典型的是,事件驅動的函數可能由於函數代碼本身拋出的錯誤而無法成功完成。可能發生這種情況的一些原因如下:

  • 該函數包含錯誤,運行時拋出異常。
  • 該函數無法到達服務端點,或在嘗試到達端點時超時。
  • 該函數有意拋出異常(例如,當參數驗證失敗時)。
  • 當用 Node.js 編寫的函數返回被拒絕的承諾或將非null值傳遞給回調時。

在上述任何一種情況下,函數默認停止執行,事件被丟棄。如果您想在發生錯誤時重試函數,可以通過設置“失敗時重試”屬性來更改默認重試策略。這會導致事件重複重試最多多天,直到函數成功完成。

啟用和禁用重試

使用 GCP 控制台

您可以在 GCP Console 中啟用或禁用重試,如下所示:

  1. 進入雲平台控制台的雲函數概覽頁面

  2. 單擊創建函數。或者,單擊現有函數以轉到其詳細信息頁面,然後單擊編輯

  3. 為您的函數填寫必填字段。

  4. 確保觸發器字段設置為基於事件的觸發器類型,例如 Cloud Pub/Sub 或 Cloud Storage。

  5. 單擊更多展開高級設置。

  6. 選中或取消選中標記為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 已被處理。
  • 處理帶外的重複函數調用。例如,有一個單獨的清理進程,在重複的函數調用後進行清理。