رویدادهای چرخه عمر برنامه افزودنی خود را مدیریت کنید

برنامه افزودنی شما می‌تواند شامل عملکردهای Cloud Tasks باشد که وقتی یک نمونه برنامه افزودنی از هر یک از رویدادهای چرخه عمر زیر می‌گذرد، فعال می‌شوند:

  • نمونه ای از برنامه افزودنی نصب شده است
  • نمونه ای از برنامه افزودنی به نسخه جدید به روز می شود
  • پیکربندی یک نمونه برنامه افزودنی تغییر کرده است

یکی از مهمترین موارد استفاده از این ویژگی، پر کردن داده ها است. به عنوان مثال، فرض کنید در حال ساختن یک برنامه افزودنی هستید که پیش نمایش تصاویر بندانگشتی از تصاویر آپلود شده در یک سطل Cloud Storage تولید می کند. کار اصلی برنامه افزودنی شما در تابعی انجام می شود که توسط رویداد onFinalize Cloud Storage راه اندازی شده است. با این حال، فقط تصاویر آپلود شده پس از نصب برنامه افزودنی پردازش می شوند. با گنجاندن تابعی در برنامه افزودنی خود که توسط رویداد چرخه حیات onInstall فعال می‌شود، می‌توانید هنگام نصب برنامه افزودنی، پیش‌نمایش‌های کوچک از هر تصویر موجود ایجاد کنید.

برخی دیگر از موارد استفاده از محرک های رویداد چرخه حیات عبارتند از:

  • تنظیم خودکار پس از نصب (ایجاد رکوردهای پایگاه داده، نمایه سازی و غیره)
  • اگر مجبور به انتشار تغییرات ناسازگار با عقب هستید، به‌طور خودکار داده‌ها را در به‌روزرسانی منتقل کنید

کنترل کننده رویدادهای چرخه حیات کوتاه مدت

اگر وظیفه شما می تواند به طور کامل در حداکثر مدت زمان Cloud Functions اجرا شود (9 دقیقه با استفاده از API نسل اول)، می توانید کنترل کننده رویداد چرخه زندگی خود را به عنوان یک تابع واحد بنویسید که در صف وظایف در رویداد 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
    
    

    می توانید توابع را برای هر یک از رویدادهای زیر ثبت کنید: onInstall ، onUpdate و onConfigure . همه این رویدادها اختیاری هستند.

  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 انجام شود، کار را به وظایف فرعی تقسیم کنید و هر کار فرعی را به ترتیب با قرار دادن کارها با روش TaskQueue.enqueue() Admin SDK انجام دهید.

به عنوان مثال، فرض کنید می خواهید داده های 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 ببینند.

اتمام موفقیت آمیز و خطاهای غیر کشنده

برای گزارش تکمیل موفقیت‌آمیز و خطاهای غیرمرگبار (خطایی که برنامه افزودنی را در حالت غیرعملکردی قرار نمی‌دهد)، از روش زمان اجرا برنامه افزودنی setProcessingState() Admin SDK استفاده کنید:

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

برای جزئیات بیشتر در مورد این پارامترها، به پیکربندی صف وظایف Cloud در اسناد Google Cloud مراجعه کنید.

سعی نکنید پارامترهای صف وظایف را با ارسال آنها به taskQueue() مشخص کنید. این تنظیمات به نفع پیکربندی در extension.yaml و تنظیمات پیش‌فرض نادیده گرفته می‌شوند.

به عنوان مثال، این کار نخواهد کرد:

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

ویژگی taskQueueTrigger در extension.yaml تنها راه برای پیکربندی صف های وظیفه یک برنامه افزودنی است.

نمونه ها

افزونه‌های رسمی storage-resize-images ، firestore-bigquery-export ، و firestore-translate-text افزونه‌ها همگی از کنترل‌کننده‌های رویداد چرخه حیات برای تکمیل داده‌ها استفاده می‌کنند.