Catch up on highlights from Firebase at Google I/O 2023. Learn more

處理您的擴展程序的生命週期事件

您的擴展可以包含Cloud Tasks 函數,這些函數在擴展實例經歷以下任何生命週期事件時觸發:

  • 安裝了一個擴展實例
  • 擴展的實例更新到新版本
  • 擴展實例的配置已更改

此功能最重要的用例之一是回填數據。例如,假設您正在構建一個擴展程序來生成上傳到 Cloud Storage 存儲桶的圖像的縮略圖預覽。您的擴展的主要工作將在由onFinalize Cloud Storage 事件觸發的函數中完成。但是,只有在安裝擴展上傳的圖像才會被處理。通過在您的擴展中包含一個由onInstall生命週期事件觸發的函數,您還可以在安裝擴展時生成任何現有圖像的縮略圖預覽。

生命週期事件觸發器的其他一些用例包括:

  • 自動化安裝後設置(創建數據庫記錄、索引等)
  • 如果您必鬚髮布向後不兼容的更改,請在更新時自動遷移數據

短期運行的生命週期事件處理程序

如果您的任務可以在最大 Cloud Functions 持續時間(使用第一代 API 時為 9 分鐘)內完全運行,您可以將生命週期事件處理程序編寫為在任務隊列onDispatch事件上觸發的單個函數:

export const myTaskFunction = functions.tasks.taskQueue()
  .onDispatch(async () => {
    // Complete your lifecycle event handling task.
    // ...

    // When processing is complete, report status to the user (see below).
  });

然後,在您的擴展程序的extension.yaml文件中,執行以下操作:

  1. 使用taskQueueTrigger屬性集將您的函數註冊為擴展資源。如果您將taskQueueTrigger設置為空映射 ( {} ),您的擴展將使用默認設置配置 Cloud Tasks 隊列;您可以選擇性地調整這些設置

    resources:
      - name: myTaskFunction
        type: firebaseextensions.v1beta.function
        description: >-
          Describe the task performed when the function is triggered by a lifecycle
          event
        properties:
          location: ${LOCATION}
          taskQueueTrigger: {}
    
  2. 將您的函數註冊為一個或多個生命週期事件的處理程序:

    resources:
      - ...
    lifecycleEvents:
      onInstall:
        function: myTaskFunction
        processingMessage: Resizing your existing images
      onUpdate:
        function: myOtherTaskFunction
        processingMessage: Setting up your extension
      onConfigure:
        function: myOtherTaskFunction
        processingMessage: Setting up your extension
    
    

    您可以為以下任何事件註冊函數: onInstallonUpdateonConfigure 。所有這些事件都是可選的。

  3. 推薦:如果您的擴展工作不需要處理任務,請添加一個用戶配置的參數,讓用戶選擇是否啟用它。

    例如,添加如下參數:

    params:
      - param: DO_BACKFILL
        label: Backfill existing images
        description: >
          Should existing, unresized images in the Storage bucket be resized as well?
        type: select
        options:
          - label: Yes
            value: true
          - label: No
            value: false
    

    在您的函數中,如果參數設置為false ,則提前退出:

    export const myTaskFunction = functions.tasks.taskQueue()
      .onDispatch(async () => {
        if (!process.env.DO_BACKFILL) {
          await runtime.setProcessingState(
            "PROCESSING_COMPLETE",
            "Existing images were not resized."
          );
          return;
        }
        // Complete your lifecycle event handling task.
        // ...
      });
    

執行長時間運行的任務

如果您的任務無法在最大 Cloud Functions 持續時間內完成,請將任務分解為子任務,並通過使用 Admin SDK 的TaskQueue.enqueue()方法將作業排隊來按順序執行每個子任務。

例如,假設您要回填 Cloud Firestore 數據。您可以使用查詢游標將文檔集合分成塊。處理完一個塊後,推進起始偏移量並將另一個函數調用入隊,如下所示:

import { getFirestore } from "firebase-admin/firestore";
import { getFunctions } from "firebase-admin/functions";

exports.backfilldata = functions.tasks.taskQueue().onDispatch(async (data) => {
  // When a lifecycle event triggers this function, it doesn't pass any data,
  // so an undefined offset indicates we're on our first invocation and should
  // start at offset 0. On subsequent invocations, we'll pass an explicit
  // offset.
  const offset = data["offset"] ?? 0;

  // Get a batch of documents, beginning at the offset.
  const snapshot = await getFirestore()
    .collection(process.env.COLLECTION_PATH)
    .startAt(offset)
    .limit(DOCS_PER_BACKFILL)
    .get();
  // Process each document in the batch.
  const processed = await Promise.allSettled(
    snapshot.docs.map(async (documentSnapshot) => {
      // Perform the processing.
    })
  );

  // If we processed a full batch, there are probably more documents to
  // process, so enqueue another invocation of this function, specifying
  // the offset to start with.
  //
  // If we processed less than a full batch, we're done.
  if (processed.length == DOCS_PER_BACKFILL) {
    const queue = getFunctions().taskQueue(
      "backfilldata",
      process.env.EXT_INSTANCE_ID
    );
    await queue.enqueue({
      offset: offset + DOCS_PER_BACKFILL,
    });
  } else {
      // Processing is complete. Report status to the user (see below).
  }
});

前一節所述,將函數添加到您的extension.yaml中。

報告狀態

當您的所有處理功能完成時,無論是成功還是錯誤,請使用 Admin SDK 的擴展運行時方法報告任務的狀態。用戶可以在 Firebase 控制台的擴展詳細信息頁面上看到此狀態。

成功完成和非致命錯誤

要報告成功完成和非致命錯誤(不會將擴展置於非功能狀態的錯誤),請使用 Admin SDK 的setProcessingState()擴展運行時方法:

import { getExtensions } from "firebase-admin/extensions";

// ...

getExtensions().runtime().setProcessingState(processingState, message);

您可以設置以下狀態:

非致命狀態
PROCESSING_COMPLETE

用於報告任務成功完成。例子:

getExtensions().runtime().setProcessingState(
  "PROCESSING_COMPLETE",
  `Backfill complete. Successfully processed ${numSuccess} documents.`
);
PROCESSING_WARNING

用於報告部分成功。例子:

getExtensions().runtime().setProcessingState(
  "PROCESSING_WARNING",
  `Backfill complete. ${numSuccess} documents processed successfully.`
    + ` ${numFailed} documents failed to process. ${listOfErrors}.`
    + ` ${instructionsToFixTheProblem}`
);
PROCESSING_FAILED

用於報告阻止任務完成的錯誤,但不要讓擴展無法使用。例子:

getExtensions().runtime().setProcessingState(
  "PROCESSING_FAILED",
  `Backfill failed. ${errorMsg} ${optionalInstructionsToFixTheProblem}.`
);

要報告確實使擴展無法使用的錯誤,請調用setFatalError()

NONE

用於清除任務的狀態。您可以選擇使用它來清除控制台的狀態消息(例如,在設置PROCESSING_COMPLETE後經過一段時間後)。例子:

getExtensions().runtime().setProcessingState("NONE");

致命錯誤

如果發生阻止擴展運行的錯誤——例如,所需的設置任務失敗——使用setFatalError()報告致命錯誤:

import { getExtensions } from "firebase-admin/extensions";

// ...

getExtensions().runtime().setFatalError(`Post-installation setup failed. ${errorMessage}`);

調整任務隊列

如果您將taskQueueTrigger屬性設置為{} ,您的擴展程序將在安裝擴展程序實例時使用默認設置提供 Cloud Tasks 隊列。或者,您可以通過提供特定值來調整任務隊列的並發限制和重試行為:

resources:
  - name: myTaskFunction
    type: firebaseextensions.v1beta.function
    description: >-
      Perform a task when triggered by a lifecycle event
    properties:
      location: ${LOCATION}
      taskQueueTrigger:
        rateLimits:
          maxConcurrentDispatches: 1000
          maxDispatchesPerSecond: 500
        retryConfig:
          maxAttempts: 100  # Warning: setting this too low can prevent the function from running
          minBackoffSeconds: 0.1
          maxBackoffSeconds: 3600
          maxDoublings: 16
lifecycleEvents:
  onInstall: 
    function: myTaskFunction
    processingMessage: Resizing your existing images
  onUpdate:
    function: myTaskFunction
    processingMessage: Setting up your extension
  onConfigure:
    function: myOtherTaskFunction
    processingMessage: Setting up your extension

有關這些參數的詳細信息,請參閱 Google Cloud 文檔中的配置 Cloud Tasks 隊列

例子

官方的storage-resize-imagesfirestore-bigquery-exportfirestore-translate-text擴展都使用生命週期事件處理程序來回填數據。