Obsługuj zdarzenia cyklu życia rozszerzenia

Twoje rozszerzenie może zawierać funkcje Cloud Tasks , które uruchamiają się, gdy instancja rozszerzenia przechodzi przez dowolne z następujących zdarzeń cyklu życia:

  • Instancja rozszerzenia jest zainstalowana
  • Instancja rozszerzenia zostanie zaktualizowana do nowej wersji
  • Konfiguracja instancji rozszerzenia została zmieniona

Jednym z najważniejszych przypadków użycia tej funkcji jest uzupełnianie danych . Załóżmy na przykład, że tworzysz rozszerzenie generujące podgląd miniatur obrazów przesłanych do zasobnika Cloud Storage. Główna praca Twojego rozszerzenia będzie wykonywana w funkcji wyzwalanej przez zdarzenie onFinalize Cloud Storage. Jednak przetwarzane będą tylko obrazy przesłane po zainstalowaniu rozszerzenia. Włączając do rozszerzenia funkcję uruchamianą przez zdarzenie cyklu życia onInstall , możesz także generować podglądy miniatur istniejących obrazów po zainstalowaniu rozszerzenia.

Niektóre inne przypadki użycia wyzwalaczy zdarzeń cyklu życia obejmują:

  • Zautomatyzuj konfigurację po instalacji (tworzenie rekordów bazy danych, indeksowanie itp.)
  • Jeśli musisz opublikować zmiany niezgodne wstecz, przeprowadź automatyczną migrację danych podczas aktualizacji

Krótkotrwałe procedury obsługi zdarzeń cyklu życia

Jeśli Twoje zadanie może zostać uruchomione w całości w maksymalnym czasie trwania Cloud Functions (9 minut przy użyciu interfejsu API pierwszej generacji), możesz napisać procedurę obsługi zdarzeń cyklu życia jako pojedynczą funkcję, która będzie wyzwalana w zdarzeniu onDispatch kolejki zadań:

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).
  });

Następnie w pliku extension.yaml wykonaj następujące czynności:

  1. Zarejestruj swoją funkcję jako zasób rozszerzenia z zestawem właściwości taskQueueTrigger . Jeśli ustawisz taskQueueTrigger na pustą mapę ( {} ), Twoje rozszerzenie udostępni kolejkę Cloud Tasks przy użyciu ustawień domyślnych; możesz opcjonalnie dostroić te ustawienia .

    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. Zarejestruj swoją funkcję jako procedurę obsługi jednego lub większej liczby zdarzeń cyklu życia:

    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
    
    

    Możesz zarejestrować funkcje dla dowolnego z następujących zdarzeń: onInstall , onUpdate i onConfigure . Wszystkie te zdarzenia są opcjonalne.

  3. Zalecane : jeśli zadanie przetwarzania nie jest wymagane do działania rozszerzenia, dodaj parametr skonfigurowany przez użytkownika , który pozwoli użytkownikom wybrać, czy je włączyć.

    Na przykład dodaj parametr podobny do następującego:

    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
    

    A w Twojej funkcji, jeśli parametr jest ustawiony na false , wyjdź wcześniej:

    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.
        // ...
      });
    

Wykonywanie długotrwałych zadań

Jeśli zadania nie można ukończyć w maksymalnym czasie trwania Cloud Functions, podziel je na podzadania i wykonaj każde podzadanie po kolei, kolejkując zadania za pomocą metody TaskQueue.enqueue() pakietu Admin SDK.

Załóżmy na przykład, że chcesz uzupełnić dane Cloud Firestore. Możesz podzielić kolekcję dokumentów na części za pomocą kursorów zapytań . Po przetworzeniu fragmentu przesuń początkowe przesunięcie i umieść w kolejce wywołanie kolejnej funkcji, jak pokazano poniżej:

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).
  }
});

Dodaj tę funkcję do pliku extension.yaml zgodnie z opisem w poprzedniej sekcji .

Stan raportowania

Gdy wszystkie funkcje przetwarzania zakończą się pomyślnie lub z błędem, zgłoś stan zadania, korzystając z metod wykonawczych rozszerzenia pakietu Admin SDK. Użytkownicy mogą zobaczyć ten stan na stronie szczegółów rozszerzenia w konsoli Firebase.

Pomyślne zakończenie i błędy niekrytyczne

Aby zgłosić pomyślne zakończenie i błędy niekrytyczne (błędy, które nie powodują przejścia rozszerzenia w stan niefunkcjonalny), użyj metody wykonawczej setProcessingState() pakietu Admin SDK:

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

// ...

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

Można ustawić następujące stany:

Stany inne niż śmiertelne
PROCESSING_COMPLETE

Służy do zgłaszania pomyślnego zakończenia zadania. Przykład:

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

Użyj, aby zgłosić częściowy sukces. Przykład:

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

Użyj, aby zgłosić błędy, które uniemożliwiają wykonanie zadania, ale nie pozostawiaj rozszerzenia bezużytecznego. Przykład:

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

Aby zgłosić błędy, które powodują , że rozszerzenie staje się bezużyteczne, wywołaj metodę setFatalError() .

NONE

Użyj, aby wyczyścić status zadania. Opcjonalnie możesz użyć tego do usunięcia komunikatu o stanie z konsoli (na przykład po upływie pewnego czasu od ustawienia PROCESSING_COMPLETE ). Przykład:

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

Fatalne błędy

Jeśli wystąpi błąd uniemożliwiający działanie rozszerzenia — na przykład nie powiedzie się wymagane zadanie instalacyjne — zgłoś błąd krytyczny za pomocą setFatalError() :

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

// ...

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

Dostrajanie kolejki zadań

Jeśli ustawisz właściwość taskQueueTrigger na {} , Twoje rozszerzenie udostępni kolejkę Cloud Tasks z ustawieniami domyślnymi po zainstalowaniu instancji rozszerzenia. Alternatywnie możesz dostroić limity współbieżności kolejki zadań i zachowanie ponawiania, podając określone wartości:

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

Aby uzyskać szczegółowe informacje na temat tych parametrów, zobacz Konfigurowanie kolejek Cloud Tasks w dokumentach Google Cloud.

Przykłady

Oficjalne storage-resize-images , firestore-bigquery-export i firestore-translate-text wykorzystują procedury obsługi zdarzeń cyklu życia do uzupełniania danych.