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ę wyzwalaną 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, umieszczając zadania w kolejce 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 niepowodzenie wymaganego zadania instalacyjnego — 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.

Nie próbuj określać parametrów kolejki zadań, przekazując je do taskQueue() . Te ustawienia są ignorowane na rzecz konfiguracji w extension.yaml i ustawień domyślnych konfiguracji.

Na przykład to nie zadziała:

export const myBrokenTaskFunction = functions.tasks
  // DON'T DO THIS IN AN EXTENSION! THESE SETTINGS ARE IGNORED.
  .taskQueue({
    retryConfig: {
      maxAttempts: 5,
      minBackoffSeconds: 60,
    },
    rateLimits: {
      maxConcurrentDispatches: 1000,
      maxDispatchesPerSecond: 10,
    },
  })
  .onDispatch(
    // ...
  );

Właściwość taskQueueTrigger w extension.yaml to jedyny sposób skonfigurowania kolejek zadań rozszerzenia.

Przykłady

Oficjalne storage-resize-images , firestore-bigquery-export i firestore-translate-text korzystają z procedur obsługi zdarzeń cyklu życia w celu uzupełnienia danych.