إعداد "إضافات Firebase" لنقل البيانات إلى "وظائف السحابة الإلكترونية"

يوضّح لك هذا الدليل كيفية نقل إضافاتك من بيئة Firebase Extensions التي تم إيقافها إلى دالة يثبّتها المستخدمون وينشرونها في قاعدة الرموز البرمجية الخاصة بهم في Cloud Functions for Firebase (الجيل الثاني).

هذا هو مسار النقل المقترَح. Firebase ستحتفظ بقائمة من الإضافات التي تتضمّن بدائل رسمية على npm، وسيرشدك هذا الدليل إلى كيفية إنشاء إضافتك.

في هذا الدليل، يتم استخدام إضافة Stream Firestore to BigQuery ‏ (firestore-bigquery-export) كمثال. ينتهي كل قسم بـ مثال عملي يعرض شكل هذه الإضافة قبل النقل وبعده، وذلك بصفتها حزمة ‎@firebase/firestore-bigquery-export.

الاشتراك للحصول على مزيد من المعلومات والمساعدة بشأن نقل الإضافات

إذا كانت لديك أسئلة حول كيفية النقل من Firebase Extensions يمكنك التواصل معنا على firebase-extensions-migrator-support-external@google.com. سنرسل أيضًا رسالة إلكترونية إلى هذه المجموعة عندما نعدّل الدليل ونضيف إليه مزيدًا من المعلومات حول تجميع دوال الجيل الثاني واختبارها وتوزيعها.

للانضمام إلى هذه المجموعة، أرسِل رسالة إلى firebase-extensions-migrator-support-external+subscribe@google.com، وسيتم الردّ عليك برسالة إلكترونية تتضمّن طلب عضوية. عليك الردّ على هذه الرسالة الإلكترونية، وليس النقر على الزر "الانضمام إلى هذه المجموعة".

قبل البدء

لإكمال عملية النقل هذه، ستستخدم الميزات التالية في Cloud Functions

  • الإعدادات المحدّدة المَعلمات. تصبح كل مَعلمة تُعلن عنها في extension.yaml مَعلمة محدّدة في رمز الحزمة.

  • أدوار إدارة الهوية وإمكانية الوصول (IAM) التصريحية وواجهات برمجة التطبيقات المطلوبة. يصبح كل دور تُعلن عنه في extension.yaml استدعاءً لـ requiresRole(...)، وتصبح كل واجهة برمجة تطبيقات استدعاءً لـ requiresAPI(...) في رمز الدالة. عند النشر، تمنح Firebase CLI الأدوار المُعلَن عنها لحساب خدمة وقت التشغيل المُدار وتفعِّل واجهات برمجة التطبيقات المُعلَن عنها نيابةً عنك.

  • أحداث مراحل النشاط لقواعد رموز Cloud Functions. Cloud Functions تتيح الآن قواعد الرموز أحداث مراحل النشاط المشابهة لـ Firebase Extensions. يمكنك الإعلان عن الإعدادات في وقت التثبيت ووقت التعديل باستخدام خطافَي مراحل النشاط afterFirstDeploy(...) وafterRedeploy(...). يحلّ هذان الخطافان محلّ lifecycleEvents التي تُعلن عنها في extension.yaml.

.

إجراء جرد للإضافة

ابدأ بإجراء جرد لإضافتك: قائمة كاملة بكل ما تُعلنه الإضافة وتُرسله وتوثّقه، بحيث يكون لكل سلوك وجهة محدّدة في دالة الجيل الثاني ولا يتم فقدان أي شيء أثناء النقل.

راجِع كلًا مما يلي، وسجِّل ما تجده:

  • extension.yaml: يُعلن عن المَعلمات والدوال والأحداث وأدوار إدارة الهوية وإمكانية الوصول وواجهات برمجة التطبيقات المطلوبة والأسرار وخطافَي مراحل النشاط.

  • functions/: يحتوي على رمز الدالة والتبعيات وإعدادات الإصدار والمشغّلات ودوال قائمة انتظار المهام.

  • README.mdوPREINSTALL.md وPOSTINSTALL.md: تحتوي على خطوات الإعداد والتحذيرات وملاحظات الفوترة.

  • scripts/: يحتوي على أي أدوات استيراد أو إعادة ملء أو إدارة الهوية وإمكانية الوصول أو إصلاح أو نقل، وأي أدوات أخرى تُرسلها مع الإضافة.

بعد ذلك، لكل عنصر في extension.yaml، حدِّد مكانه في حزمة npm:

  • تحويل إعدادات المستخدم إلى مَعلمات Cloud Functions (القسم 5)

  • تحويل الأسرار إلى Cloud Functions أسرار (القسم 6)

  • تحويل أدوار إدارة الهوية وإمكانية الوصول إلى إعلانات requiresRole(...) (القسم 8)

  • تحويل واجهات برمجة التطبيقات المطلوبة من Google إلى إعلانات requiresAPI(...) عند الاقتضاء (القسم 8)

  • تحويل خطافَي التثبيت والتعديل إلى إعلانات afterFirstDeploy(...) وafterRedeploy(...) (القسم 8)

مثال عملي: Stream Firestore to BigQuery

تؤدي قراءة firestore-bigquery-export/extension.yaml وfunctions/ إلى هذا الجرد:

في extension.yaml العدد / القيمة مكانها
params 25 (COLLECTION_PATH وDATASET_ID وTABLE_ID وDATASET_LOCATION وVIEW_TYPE و…) Cloud Functions مَعلمات (القسم 5)
apis bigquery.googleapis.com ‫requiresAPI(...) (القسم 7)
roles bigquery.dataEditor وdatastore.user وbigquery.user ‫requiresRole(...) (القسم 7)
resources مشغّل حدث واحد (fsexportbigquery) + دوال قائمة انتظار المهام (initBigQuerySync وsetupBigQuerySync) دوال الحزمة المُصدَّرة (القسم 3)
lifecycleEvents onInstall ← initBigQuerySync وonUpdate / onConfigure ← setupBigQuerySync afterFirstDeploy / afterRedeploy (القسم 9)
scripts/ ‫import/ (إعادة الملء) وgen-schema-view/ يتم الاحتفاظ بها كنصوص برمجية (خارج النطاق هنا)

لا تُعلن الإضافة عن أي مَعلمات من النوع secret، لذا ليس هناك ما يجب نقله في القسم 6 من هذا الدليل. إنّ مشغّل الحدث هو من الجيل الثاني، بينما لا تزال دوال قائمة المهام من الجيل الأول (ذات صلة في القسم 3).

تعديل package.json

عدِّل ملف package.json الخاص بإضافتك. إذا كنت تنقل إضافة واحدة، يمكن أن يكون هذا الملف هو package.json الجذر. إذا كنت تنقل العديد من الإضافات في مستودع واحد، امنح كل إضافة حزمة خاصة بها.

الحد الأدنى لإصدارات حزمة تطوير البرامج (SDK). أعلِن عن firebase-functions >= 7.3 وfirebase-admin >= 14.2.0 كتبعيات. أعلِن أيضًا عن إصدار firebase-functions كاعتماد نظير.

{
  "name": "<package-name>",
  "version": "1.0.0",
  "main": "lib/index.js",
  "types": "lib/index.d.ts",
  "exports": {
    ".": {
      "types": "./lib/index.d.ts",
      "default": "./lib/index.js"
    }
  },
  "engines": {
    "node": ">=22"
  },
  "peerDependencies": {
    "firebase-functions": "^7.3.0"
  },
  "dependencies": {
    "firebase-functions": "^7.3.0",
    "firebase-admin": "^14.2.0"
  }
}

أعلِن عن وظائف Firebase كاعتمادية نظيرة بالإضافة إلى اعتماديتك العادية، حتى يتضمّن مشروع Cloud Functions الخاص بالمستخدمين الإصدار نفسه من حزمة تطوير البرامج (SDK) التي تم استخدامها لكتابة مكتبتك.

مثال عملي: Stream Firestore to BigQuery

قبل إنّ ملف functions/package.json الخاص بالإضافة خاص، ويسمّي معرّف الإضافة، ويُعلن عن firebase-functions كاعتماد مباشر:

{
  "name": "firestore-bigquery-export",
  "main": "lib/index.js",
  "private": true,
  "dependencies": {
    "@firebaseextensions/firestore-bigquery-change-tracker": "^2.0.4",
    "firebase-admin": "^14.2.0",
    "firebase-functions": "^6.3.2"
  }
}

بعد حزمة قابلة للنشر: اسم ذو نطاق وخريطة عمليات تصدير وfirebase-functions تم نقله إلى peerDependencies:

{
  "name": "@firebase/firestore-bigquery-export",
  "version": "0.1.0",
  "main": "lib/index.js",
  "types": "lib/index.d.ts",
  "exports": {
    ".":     { "types": "./lib/index.d.ts", "default": "./lib/index.js" },  },
  "engines": { "node": ">=22" },
  "peerDependencies": { "firebase-functions": "^7.3.0" },
  "dependencies": {
      "@firebaseextensions/firestore-bigquery-change-tracker": "^2.0.4",
      "firebase-admin": "^14.2.0",
      "firebase-functions": "^7.3.0"
    }
}

ترقية الدوال من الجيل الأول إلى الجيل الثاني

إذا كانت إضافتك لا تزال تُصدِّر دوال الجيل الأول، عليك تحويل كل دالة إلى ما يعادلها في الجيل الثاني. يمكنك الاستيراد من وحدات firebase-functions/...، وتمرير إعدادات وقت التشغيل في خيارات الدالة.

يمكنك تقليل جهود إعادة الكتابة باستخدام ميزة إلغاء بنية الحدث التي تم تصحيحها في الجيل الثاني وتجنُّب إعادة كتابة منطق الدالة لأنّ حزمة تطوير البرامج (SDK) للجيل الثاني تعرض الآن مَعلمات الإصدار الأول كحقول في عنصر الحدث ما يسمح لك باستخدام مَعلمات تم إلغاء بنيتها أو مَعلمات مُسمّاة والحفاظ على منطق نشاطك التجاري بدون تغيير.

قبل الجيل الأول:

import * as functions from "firebase-functions/v1";

export const sync = functions.firestore
  .document("{collectionId}/{documentId}")
  .onWrite(async (change, context) => {
    await handleWrite(change.before, change.after, context.params);
  });

بعد الجيل الثاني:

import { onDocumentWritten } from "firebase-functions/firestore";

export const syncV2 = onDocumentWritten(
  { document: "{collectionId}/{documentId}" },
  async ({change,context}) =>
    await handleWrite(change.before, change.after, context.params);
);
.

يمكنك الاطّلاع على مقارنة Cloud Functions الإصدارات للحصول على قائمة شاملة بالاختلافات بين دوال الجيل الأول والجيل الثاني.

تحويل مَعلمات الإضافة وأسرارها

تحويل المَعلمات

تصبح كل مَعلمة تُعلن عنها في extension.yaml مَعلمة في Cloud Functions.

يمكنك تحويل عمليات القراءة المباشرة للبيئة:

const collectionPath = process.env.COLLECTION_PATH;

إلى Cloud Functions مَعلمات:

import { defineString } from "firebase-functions/params";
import { onDocumentWritten} from "firebase-functions/firestore";

const collectionPath = defineString("COLLECTION_PATH");

// Pass the param directly when used as a placeholder (e.g. trigger path)
export const sync = onDocumentWritten(
  { document: collectionPath },
  async (event) => {
    // Call .value() to read the string inside a handler
    const path = collectionPath.value();
    await handleWrite(path, event);
  }
);

استخدِم collectionPath.value() لقراءة السلسلة داخل معالج، واستخدِم collectionPath مباشرةً عندما يكون العنصر النائب متوقعًا، مثل مسار مشغّل دالة.

تكتشف Firebase CLI مَعلماتك وتقرأ قيمها من .env، .env.projectId، أو تطلب من المستخدمين إدخالها أثناء النشر. احتفِظ بأسماء المَعلمات نفسها، حتى يتم نقل القيم من عملية التثبيت الحالية.

من المهم عدم تغيير أسماء المَعلمات المُعلَن عنها في الرمز على الإطلاق. سيؤدي نقل الإضافة إلى الاحتفاظ تلقائيًا بقيمة المَعلمة الحالية للمستخدم النهائي، ولكن فقط عندما تكون الأسماء بدون تغيير.

مثال عملي: Stream Firestore to BigQuery قبل مَعلمة مُعلَن عنها في extension.yaml، تتم قراءتها كمتغيّر بيئة غير مُعالَج في config.ts:

# extension.yaml
-   param: COLLECTION_PATH
  label: Collection path
  type: string
  required: true
// functions/src/config.ts
collectionPath: process.env.COLLECTION_PATH,

بعدdefineString واحد: تكتشفه واجهة سطر الأوامر وتقرأه من .env:

// src/config.ts
import { defineString } from "firebase-functions/params";

collectionPath: defineString("COLLECTION_PATH", {
  label: "Collection path",
  // We now support "nonEmpty: true" to ensure a value other than the empty string
  // is entered, analagous to "required: true" in extensions.yaml
  input: { text: { nonEmpty: true} }
}),

اسم المَعلمة بدون تغيير، لذا سيظل ملف .env الحالي يعمل.

تحويل الأسرار

في extension.yaml، يمكنك الإعلان عن الأسرار باستخدام type: secret. يخزّن وقت تشغيل "الإضافات" هذه الأسرار ويربطها، لذا يمكن لرمز إضافتك قراءة process.env.PARAM_NAME مباشرةً. في قاعدة رموز Cloud Functions نموذجية، يمكنك الإعلان عن كل سر وربطه بشكلٍ صريح:

import { defineSecret } from "firebase-functions/params";
import { onRequest } from "firebase-functions/https";

const apiKey = defineSecret("API_KEY");
export const fn = onRequest({ secrets: [apiKey] }, handler);

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

مثال عملي: Trigger Email From Cloud Firestore

قبل ‫MAIL_COLLECTION وSMTP_PASSWORD تتم قراءتهما كمتغيّرات بيئة غير مُعالَجة في config.ts:

# extension.yaml
-   param: MAIL_COLLECTION
  label: Email documents collection
  type: string
  default: mail
  required: true

-   param: SMTP_PASSWORD
  label: SMTP password
  type: secret
// functions/src/config.ts
mailCollection: process.env.MAIL_COLLECTION,
smtpPassword: process.env.SMTP_PASSWORD,

بعدdefineString واحد وdefineSecret واحد: تكتشف واجهة سطر الأوامر كليهما وتقرأهما من .env

import { defineString, defineSecret } from "firebase-functions/params";
import { onDocumentWritten } from "firebase-functions/firestore";

const mailCollection = defineString("MAIL_COLLECTION",{ label: "Email documents collection",
 default: "mail"
});

const smtpPassword = defineSecret("SMTP_PASSWORD", { label: "SMTP password" });

export const processQueue = onDocumentWritten(
  { document: `${mailCollection}/{documentId}`, secrets: [smtpPassword] },
  async (event) => {
    const collection = mailCollection.value();
    const password = smtpPassword.value();
    // ...
  }
);

نقل عمليات استدعاء قائمة المهام الداخلية

تُضيف بعض الإضافات العمل إلى قوائم المهام الخاصة بها من داخل رمز الدالة الخاص بها، باستخدام Firebase Admin SDK. يختلف ذلك عن تلقّي مهمة تم إرسالها (موضّح في قسمَي ترقية الدوال و تحويل خطافَي مراحل النشاط). هنا يكون الرمز هو المنتِج الذي يستدعي queue.enqueue(...).

كانت الإصدارات السابقة من Admin SDK تتطلب من الإضافات تمرير معرّف مثيل الإضافة الخاص بها كـمعلّمة ثانية لاستهداف دالة "قائمة المهام" في الإضافة نفسها. اعتبارًا من `firebase-admin` 14.2.0، لم يعد ذلك مطلوبًا ولا يُنصح به. ستستهدف Task Queue API الآن قوائم المهام في السياق نفسه (مثل الإضافة) تلقائيًا. من الآمن والمشجّع إزالة هذه المَعلمة في الرمز البرمجي سواء كإضافة أو كدوال مستقلة. تضمن إزالة هذه المَعلمة إمكانية النقل والتوافق مع الإصدارات المستقبلية.

تظل كل المعلومات الأخرى حول استدعاء enqueue كما هي: مسار المورد للمواقع الجغرافية أو region أو الدوال أو name، وحِمل المهمة، ومنطق إعادة المحاولة.

يمكنك الاطّلاع على /docs/functions/task-functions لمزيد من التفاصيل حول إضافة الدوال إلى قائمة الانتظار باستخدام Cloud Tasks.

قبل إضافة من الجيل الأول

import { getFunctions } from "firebase-admin/functions";

const queue = getFunctions().taskQueue(
  `locations/${config.location}/functions/syncBigQuery`,
  process.env.EXT_INSTANCE_ID, // extension instance ID, injected by the runtime
);
await queue.enqueue(taskData);

بعد إضافة من الجيل الثاني

import { getFunctions } from "firebase-admin/functions";
import { region } from "firebase-functions/params";

const queue = getFunctions().taskQueue(
  `locations/${region.value()}/functions/syncBigQuery`);
await queue.enqueue(taskData);

إذا كان استدعاء enqueue يستهدف قاعدة رموز برمجية ذات بادئة، تتم أيضًا إضافة بادئة إلى اسم الدالة التي تم اكتشافها (على سبيل المثال، orders-syncBigQuery).

الإعلان عن واجهات برمجة التطبيقات المطلوبة وأدوار إدارة الهوية وإمكانية الوصول

انقُل متطلبات إدارة الهوية وإمكانية الوصول وواجهة برمجة التطبيقات الخاصة بإضافتك من extension.yaml إلى الرمز:

import { requiresAPI, requiresRole } from "firebase-functions"

requiresAPI("bigquery.googleapis.com", "Needed to write changelog rows");
requiresRole("roles/bigquery.dataEditor");
requiresRole("roles/bigquery.user");

باستخدام الأمان التصريحي، تنشئ Firebase CLI حساب خدمة وقت تشغيل مُدار لقاعدة الرموز البرمجية أو تعدّله، وتمنحه اتحاد جميع الأدوار المُعلَن عنها. يمكنك توضيح للمستخدمين أنّ جميع الدوال في قاعدة الرموز البرمجية تعمل بهذه الأدوار، ما لم تكن واجهة برمجة التطبيقات النهائية تتيح نموذجًا أضيق نطاقًا.

مثال عملي: Stream Firestore to BigQuery

قبل تم الإعلان عنها في extension.yaml، وفعّل وقت تشغيل "الإضافات" واجهة برمجة التطبيقات ومنح الأدوار إلى حساب مُدار:

apis:
  -   apiName: bigquery.googleapis.com
roles:
  -   role: bigquery.dataEditor
  -   role: datastore.user
  -   role: bigquery.user

بعد تم الإعلان عنها في الرمز باستخدام requiresAPI وrequiresRole:

import { requiresAPI, requiresRole } from "firebase-functions/";
requiresAPI("bigquery.googleapis.com",
  "Needed to write changelog rows and views");
requiresRole("roles/biguqery.dataEditor");
requiresRole("roles/datastore.user");
requiresRole("roles/bigquery.user");

تحويل خطافَي مراحل النشاط

إذا كانت إضافتك تستدعي getExtensions().runtime()، على سبيل المثال setProcessingState أو setFatalError، عليك حذف عمليات الاستدعاء هذه، لأنّها ستعرض خطأ إذا تم استدعاؤها من دالة من الجيل الثاني تم نشرها بشكلٍ عادي. تستند حالة مراحل النشاط الآن إلى afterFirstDeploy وafterRedeploy عندما لا يتم استخدام تتبُّع الحالة هذا.

Firebase Extensions يمكن أن تُشغّل عملية الإعداد عندما يثبّت المستخدم إضافة أو يعدّلها أو يعيد ضبطها. في حزمة npm، يمكنك الإعلان عن إجراءات مراحل النشاط المكافئة في الرمز.

للإعداد لمرة واحدة:

import { afterFirstDeploy } from "firebase-functions/lifecycle";
import { onTaskDispatched } from "firebase-functions/tasks";

export const runInitialSetup = onTaskDispatched(async (request) => {
  await initializeResources(request.data);
});

afterFirstDeploy({
  task: {
    function: "runInitialSetup",
    body: {}
  }
});

لتعديلات الإعدادات أو الرمز:

import { afterRedeploy } from "firebase-functions/lifecycle";

afterRedeploy({
  task: {
    function: "runInitialSetup",
    body: { reconcile: true }
  }
});

اجعل إجراءات مراحل النشاط غير حساسة للتكرار. قد يحتاج المستخدمون إلى إعادة تشغيلها يدويًا إذا تعذّر الإرسال أو التنفيذ:

firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME
firebase functions:lifecycle:run afterRedeploy CODEBASE_NAME

مثال عملي: Stream Firestore to BigQuery

قبلlifecycleEvents في extension.yaml، يتم تشغيلها بواسطة وقت تشغيل "الإضافات":

lifecycleEvents:
  onInstall:
    function: initBigQuerySync
    processingMessage: Configuring BigQuery Sync.
  onUpdate:
    function: setupBigQuerySync
    processingMessage: Configuring BigQuery Sync
  onConfigure:
    function: setupBigQuerySync
    processingMessage: Configuring BigQuery Sync

بعد تم الإعلان عنها في الرمز، وتوفّر المهمة BigQuery عند النشر الأول:

import { afterFirstDeploy, afterRedeploy } from "firebase-functions/lifecycle";

afterFirstDeploy({ task: { function: "initBigQuerySync" } });
afterRedeploy({ task: { function: "setupBigQuerySync" } });

إنّ عملية توفير الموارد غير حساسة للتكرار، لذا تؤدي إعادة تشغيلها إلى مطابقة مجموعة البيانات والجدول وطرق العرض. يمكن للمستخدمين إعادة تشغيلها يدويًا باستخدام firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME.

توضيح عملية الإعداد للمستخدمين

  • اكتب ملف README للحزمة يوضّح، كحد أدنى:

  • قيم .env التي تتطلبها الحزمة

  • الأسرار التي تتطلبها الحزمة وكيفية نقل قيم الأسرار الحالية

  • أدوار إدارة الهوية وإمكانية الوصول التي تُعلن عنها الحزمة باستخدام requiresRole(...)

  • واجهات برمجة التطبيقات من Google التي تفعِّلها الحزمة أو تتطلبها

  • خطافَي مراحل النشاط اللذين تُعلنهما الحزمة وكيفية إعادة تشغيلهما يدويًا

  • ملاحظات الفوترة

  • التغييرات التي تم إجراؤها مقارنةً بالإضافة الأصلية

مثال عملي: Stream Firestore to BigQuery

يُرسِل ملف README الخاص بالحزمة جدولًا ملموسًا يوضّح "ما الذي تغيّر":

حسب حالة العين بصفتها الإضافة بصفتها ‎ @firebase/firestore-bigquery-export
الإعداد مَعلمات الإضافة مَعلمات الدوال من خلال .env
إدارة الهوية وإمكانية الوصول تم منحها من خلال "الإضافات" ‫requiresRole(...)، يتم تطبيقها عند النشر
إدارة الحسابات مهمة مراحل النشاط من خلال "الإضافات" مهمة afterFirstDeploy / afterRedeploy
أسماء الدوال ext-instanceId-fsexportbigquery fsexportbigquery (مع بادئة اختيارية)

اختبار دالة الجيل الثاني

يجب أن يكون لديك الآن دالة من الجيل الثاني، وعند نشرها، ستتصرّف تمامًا مثل عملية تثبيت جديدة لإضافتك. الخطوة الأخيرة هي التحقّق من أي مشاكل تم إدخالها عن طريق الخطأ أثناء النقل وإصلاحها.

تأكَّد من استخدام firebase-tools >= 15.24.0، وانشر دالة الجيل الثاني التي تم تحويلها في مشروع اختبار يتضمّن الموارد المناسبة لاختبار سلوكها. إذا كان لديك مشروع اختبار تم إعداده من قبل لاختبار إضافتك، استخدِم الأمر:

firebase deploy --only functions

بعد إدخال هذا الأمر، املأ المعالج الناتج الذي يطلب منك قيم المَعلمات بالطريقة نفسها التي كنت ستملأ بها نموذج التثبيت في Firebase console للإضافة.

مثال عملي: Stream Firestore to BigQuery

نتحقّق من عملية المزامنة من Cloud Firestore إلى BigQuery بشكلٍ كامل:

  1. في Cloud Firestore console، أنشِئ المجموعة التي ضبطتها على COLLECTION_PATH (المستخدمون) إذا لم تكن موجودة من قبل.
  2. أنشِئ مستندًا باسم bigquery-mirror-test يحتوي على أي حقول بأي قيم.
  3. في BigQuery console، استخدِم طلب بحث في جدول سجلّ التغييرات الأولي. يجب أن يحتوي على صف واحد يسجّل عملية إنشاء المستند:
SELECT * FROM `PROJECT_ID.analytics.users_raw_changelog`
  1. استخدِم طلب بحث في آخر طريقة عرض، والتي يجب أن تعرض آخر حدث تغيير لـ المستند الوحيد الحالي: bigquery-mirror-test
SELECT * FROM `PROJECT_ID.analytics.users_raw_latest`
  1. احذف المستند bigquery-mirror-test في Cloud Firestore. سيختفي من آخر طريقة عرض، وسيتم إلحاق حدث DELETE بجدول سجلّ التغييرات الأولي.

يمكنك فحص السجلّ الكامل لمستند واحد باستخدام:

SELECT *
   FROM `PROJECT_ID.analytics.users_raw_changelog`
   WHERE document_name = "bigquery-mirror-test"
   ORDER BY timestamp ASC

الاختلافات عن اختبار الإضافة:

  • يتم نشر المشغّل باسم fsexportbigquery (مع بادئة اختيارية لقاعدة الرموز البرمجية)، وليس ext-&lt;instanceId&gt;-fsexportbigquery. ابحث عن هذا الاسم في الـ Cloud Functions dashboard وسجلّاتها.
  • سيعمل الرمز الآن في الـ Firebase Local Emulator Suite كدوال عادية. يمكنك ضبط قيمة المَعلمات لاستخدامها في المحاكي باستخدام .env.local. يمكنك أيضًا إجراء اختبارات الوحدة للرمز باستخدام حزمة firebase-functions-test SDK كما هو موضّح في اختبار الوحدة في Cloud Functions
  • لم يعد وقت تشغيل "الإضافات" هو الذي يشغّل عملية توفير الموارد. إذا كان جدول سجلّ التغييرات غير متوفّر بعد النشر، أعِد تشغيل مهمة الإعداد يدويًا: firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME. إنّ المهمة غير حساسة للتكرار، لذا تؤدي إعادة تشغيلها إلى مطابقة مجموعة البيانات والجدول وطرق العرض.
  • تأتي قيم المَعلمات من .env بدلاً من نموذج التثبيت، لذا لن تكون عمليات إعادة تشغيل firebase deploy تفاعلية بعد إكمال .env.