التعامل مع أحداث مراحل نشاط الإضافة

يمكن أن تتضمّن إضافتك وظائف Cloud Tasks التي يتم تفعيلها عندما تمرّ إحدى نُسخ الإضافة بأي من أحداث Cloud Tasks التالية:

  • تم تثبيت نسخة من الإضافة
  • تحديث نسخة من الإضافة إلى إصدار جديد
  • تم تغيير إعدادات مثيل الإضافة

من أهم حالات استخدام هذه الميزة هي إضافة بيانات سابقة. على سبيل المثال، لنفترض أنّك بصدد إنشاء إضافة تنشئ معاينات للصور المصغّرة للصور المحمَّلة إلى حزمة Cloud Storage. سيتم تنفيذ العمل الرئيسي للإضافه في دالة يتم تنشيطها من خلال الحدث onFinalize Cloud Storage. ومع ذلك، لن تتم معالجة سوى الصور التي تم تحميلها بعد تثبيت الإضافة. من خلال تضمين وظيفة يتم تنشيطها من خلال onInstall حدث دورة الحياة، يمكنك أيضًا إنشاء معاينات للصور المصغّرة لأي صور حالية عند تثبيت الإضافة.

تشمل بعض حالات الاستخدام الأخرى لعوامل تشغيل أحداث دورة النشاط ما يلي:

  • إعداد الإعدادات بعد التثبيت تلقائيًا (إنشاء سجلات قاعدة البيانات والفهرسة وما إلى ذلك)
  • إذا كان عليك نشر تغييرات غير متوافقة مع الإصدارات القديمة، يمكنك نقل البيانات تلقائيًا عند إجراء التحديثات.

معالِجات أحداث مراحل النشاط التي تستغرق وقتًا قصيرًا

إذا كان بإمكان مهمتك أن تعمل بالكامل خلال أقصى مدة Cloud Functions (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
    
    

    يمكنك تسجيل الدوال لأيّ من الأحداث التالية: 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 كما هو موضّح في القسم السابق.

حالة الإبلاغ

عند اكتمال جميع دوال المعالجة، سواءً بنجاح أو مع خطأ، أبلِغ عن حالة المهمة باستخدام methods لوقت تشغيل الإضافة في حزمة Admin SDK. يمكن للمستخدمين الاطّلاع على هذه الحالة في صفحة تفاصيل الإضافة في Firebase console.

اكتمال العملية بنجاح والأخطاء غير الخطيرة

للإبلاغ عن اكتمال التنفيذ الناجح والأخطاء غير المميتة (الأخطاء التي لا تؤدي إلى وضع الإضافة في حالة عدم الوظائف)، استخدِم setProcessingState()طريقة وقت تشغيل الإضافة في حزمة تطوير البرامج (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 على {}، ستنشئ الإضافة ملفًا للانتظار في "مهام Google" باستخدام الإعدادات التلقائية عند تثبيت مثيل الإضافة. بدلاً من ذلك، يمكنك ضبط حدود معالجة المهام المتزامنة وسلوك إعادة المحاولة في قائمة المهام من خلال تقديم قيم محدّدة:

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 Tasks في مستندات 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 معالجات أحداث مراحل النشاط لاسترداد البيانات السابقة.