Menangani peristiwa siklus proses ekstensi

Ekstensi Anda dapat mencakup fungsi Cloud Tasks yang terpicu saat instance ekstensi melewati salah satu peristiwa siklus proses berikut:

  • Instance ekstensi diinstal
  • Instance ekstensi diperbarui ke versi baru
  • Konfigurasi instance ekstensi diubah

Salah satu kasus penggunaan terpenting dari fitur ini adalah mengisi ulang data. Misalnya, Anda sedang mem-build ekstensi yang menghasilkan pratinjau thumbnail gambar yang diupload ke bucket Cloud Storage. Pekerjaan utama ekstensi Anda akan dilakukan dalam fungsi yang dipicu oleh peristiwa Cloud Storage onFinalize. Namun, hanya gambar yang diupload setelah ekstensi diinstal yang akan diproses. Dengan menyertakan fungsi yang dipicu oleh peristiwa siklus proses onInstall ke dalam ekstensi, Anda juga dapat membuat pratinjau thumbnail gambar yang sudah ada saat ekstensi diinstal.

Beberapa kasus penggunaan lainnya dari pemicu peristiwa siklus proses mencakup:

  • Mengotomatiskan penyiapan pascapenginstalan (membuat catatan database, pengindeksan, dll.)
  • Jika Anda harus memublikasikan perubahan yang tidak kompatibel dengan versi sebelumnya, migrasikan data secara otomatis saat update

Pengendali peristiwa siklus proses jangka pendek

Jika tugas Anda dapat berjalan sepenuhnya dalam durasi Cloud Functions maksimum (9 menit menggunakan API generasi pertama), Anda dapat menulis pengendali peristiwa siklus proses sebagai fungsi tunggal yang memicu peristiwa onDispatch task queue:

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

Kemudian, di file extension.yaml ekstensi, lakukan hal berikut:

  1. Daftarkan fungsi Anda sebagai resource ekstensi dengan properti taskQueueTrigger yang ditetapkan. Jika Anda menetapkan taskQueueTrigger ke peta kosong ({}), ekstensi Anda akan menyediakan antrean Cloud Tasks menggunakan setelan default; Anda dapat secara opsional menyesuaikan setelan ini.

    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. Daftarkan fungsi Anda sebagai pengendali untuk satu atau beberapa peristiwa siklus proses:

    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
    
    

    Anda dapat mendaftarkan fungsi untuk salah satu peristiwa berikut: onInstall, onUpdate, dan onConfigure. Semua peristiwa ini bersifat opsional.

  3. Direkomendasikan: Jika tugas pemrosesan tidak wajib ada agar ekstensi Anda berfungsi, tambahkan parameter yang dikonfigurasi pengguna yang memungkinkan pengguna memilih apakah akan mengaktifkannya atau tidak.

    Misalnya, tambahkan parameter seperti berikut:

    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
    

    Dan di fungsi Anda, jika parameter ditetapkan ke false, keluar lebih awal:

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

Melakukan tugas yang berjalan lama

Jika tugas Anda tidak dapat diselesaikan dalam durasi Cloud Functions maksimum, pecah tugas ke dalam beberapa subtugas dan lakukan setiap subtugas secara berurutan dengan mengantrekan tugas menggunakan metode TaskQueue.enqueue() Admin SDK.

Misalnya, Anda ingin mengisi ulang data Cloud Firestore. Anda dapat membagi koleksi dokumen menjadi beberapa bagian menggunakan query cursor. Setelah memproses satu bagian, majukan offset awal ke proses selanjutnya dan antrekan pemanggilan fungsi lainnya seperti yang ditunjukkan di bawah ini:

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

Tambahkan fungsi ke extension.yaml seperti yang dijelaskan di bagian sebelumnya.

Status pelaporan

Setelah semua fungsi pemrosesan selesai, baik berhasil atau mengalami error, laporkan status tugas menggunakan metode runtime ekstensi Admin SDK. Pengguna dapat melihat status ini di halaman detail ekstensi di Firebase console.

Penyelesaian yang berhasil dan error non-fatal

Untuk melaporkan keberhasilan penyelesaian dan error non-fatal (error yang tidak menempatkan ekstensi ke status tidak berfungsi), gunakan metode runtime ekstensi setProcessingState() Admin SDK:

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

// ...

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

Anda dapat menetapkan status berikut:

Status non-fatal
PROCESSING_COMPLETE

Gunakan untuk melaporkan penyelesaian tugas yang berhasil. Contoh:

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

Gunakan untuk melaporkan keberhasilan sebagian. Contoh:

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

Gunakan untuk melaporkan error yang mencegah tugas diselesaikan, tetapi jangan biarkan ekstensi tidak dapat digunakan. Contoh:

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

Untuk melaporkan error yang memang menyebabkan ekstensi tidak dapat digunakan, panggil setFatalError().

NONE

Gunakan untuk menghapus status tugas. Secara opsional, Anda dapat menggunakannya untuk menghapus pesan status dari konsol (misalnya, setelah beberapa waktu berlalu sejak menyiapkan PROCESSING_COMPLETE). Contoh:

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

Error fatal

Jika terjadi error yang mencegah ekstensi berfungsi—misalnya, tugas penyiapan yang wajib mengalami kegagalan—laporkan error fatal dengan setFatalError():

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

// ...

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

Menyesuaikan task queue

Jika Anda menetapkan properti taskQueueTrigger ke {}, ekstensi Anda akan menyediakan antrean Cloud Tasks dengan setelan default saat instance ekstensi diinstal. Atau, Anda dapat menyesuaikan batas serentak dan perilaku percobaan ulang task queue dengan memberikan nilai tertentu:

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

Baca artikel Mengonfigurasi antrean Cloud Tasks di dokumen Google Cloud untuk mengetahui detail tentang parameter ini.

Jangan mencoba menentukan parameter task queue dengan meneruskannya ke taskQueue(). Setelan ini diabaikan untuk mendukung konfigurasi di extension.yaml dan konfigurasi default.

Misalnya, hal berikut tidak akan berfungsi:

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

Properti taskQueueTrigger di extension.yaml adalah satu-satunya cara untuk mengonfigurasi antrean tugas ekstensi.

Contoh

Semua ekstensi storage-resize-images, firestore-bigquery-export, dan firestore-translate-text resmi menggunakan pengendali peristiwa siklus proses untuk mengisi ulang data.