تعامل مع أحداث دورة حياة ملحقك

يمكن أن يتضمن ملحقك وظائف Cloud Tasks التي يتم تشغيلها عندما يمر مثيل الملحق بأي من أحداث دورة الحياة التالية:

  • تم تثبيت مثيل للملحق
  • يتم تحديث مثيل الامتداد إلى إصدار جديد
  • تم تغيير تكوين مثيل الملحق

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

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

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

معالجات أحداث دورة الحياة قصيرة المدى

إذا كان من الممكن تشغيل مهمتك بالكامل خلال الحد الأقصى لمدة وظائف السحابة (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 على الخريطة الفارغة ( {} )، فسيقوم ملحقك بتوفير قائمة انتظار المهام السحابية باستخدام الإعدادات الافتراضية؛ يمكنك ضبط هذه الإعدادات بشكل اختياري.

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

أداء المهام الطويلة الأمد

إذا لم يكن من الممكن إكمال مهمتك خلال الحد الأقصى لمدة وظائف السحابة، فقسم المهمة إلى مهام فرعية وقم بتنفيذ كل مهمة فرعية بالتسلسل عن طريق وضع المهام في قائمة الانتظار باستخدام طريقة 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 الخاص بك كما هو موضح في القسم السابق .

حالة الإبلاغ

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

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

راجع تكوين قوائم انتظار المهام السحابية في مستندات 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 معالجات أحداث دورة الحياة لملء البيانات.