ترقية وظائف Node.js من الجيل الأول إلى الجيل الثاني

على التطبيقات التي تستخدم حاليًا وظائف الجيل الأول التفكير في نقل بياناتها إلى وظائف الجيل الثاني باستخدام التعليمات الواردة في هذا الدليل. تستخدِم الدوالّ من الجيل الثاني Cloud Run لتوفير أداء أفضل وإعدادات أفضل ومراقبة أفضل وغير ذلك.

تفترض الأمثلة الواردة في هذه الصفحة أنّك تستخدِم JavaScript مع وحدات CommonJS (require عمليات استيراد الأنماط)، ولكن تنطبق المبادئ نفسها على JavaScript مع ESM (import … from عمليات استيراد الأنماط) وTypeScript.

عملية نقل البيانات

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

التحقّق من إصدارات Firebase CLI وfirebase-function

تأكَّد من استخدام الإصدار 12.00 على الأقل من واجهة Firebase CLI و4.3.0 الإصدار 4.3.0.firebase-functions سيتوافق أي إصدار أحدث مع الجيل الثاني وكذلك الجيل الأول.

تعديل عمليات الاستيراد

يتم استيراد الدوالّ من الجيل الثاني من حزمة v2 الفرعية في حزمة تطوير البرامج (SDK) firebase-functions. إنّ مسار الاستيراد المختلف هذا هو كل ما تحتاجه واجهة Firebase CLI لتحديد ما إذا كان يجب نشر رمز الدالة كدالة من الجيل الأول أو الثاني.

تكون الحزمة الفرعية v2 وحدات، وننصح باستيراد الوحدت المحدّدة التي تحتاج إليها فقط.

الإصدار السابق: الجيل الأول

const functions = require("firebase-functions/v1");

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

// explicitly import each trigger
const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");

تعديل تعريفات عوامل التفعيل

بما أنّ حزمة تطوير البرامج (SDK) من الجيل الثاني تفضّل عمليات الاستيراد المُجمَّعة، عدِّل تعريفات المشغِّلات لتمثل عمليات الاستيراد التي تم تغييرها في الخطوة السابقة.

تم تغيير الوسيطات التي يتم تمريرها إلى وظائف الاستدعاء لبعض عوامل التفعيل. في هذا المثال، يُرجى العلم أنّه تم دمج الوسائط لطلب إعادة الاتصال onDocumentCreated في عنصر event واحد. بالإضافة إلى ذلك، تحتوي بعض عوامل التفعيل على ميزات إعداد جديدة ملائمة، مثل خيار cors عامل التفعيل onRequest.

الإصدار السابق: الجيل الأول

const functions = require("firebase-functions/v1");

exports.date = functions.https.onRequest((req, res) => {
  // ...
});

exports.uppercase = functions.firestore
  .document("my-collection/{docId}")
  .onCreate((change, context) => {
    // ...
  });

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

const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");

exports.date = onRequest({cors: true}, (req, res) => {
  // ...
});

exports.uppercase = onDocumentCreated("my-collection/{docId}", (event) => {
  /* ... */
});

استخدام الإعدادات المُستندة إلى مَعلمات

تتوقف دوال الجيل الثاني عن استخدام functions.config لصالح واجهة أكثر أمانًا لتحديد مَعلمات الضبط بشكل صريح داخل قاعدة بياناتك. باستخدام وحدة params الجديدة، تحظر وحدة التحكّم من سطر الأوامر عملية النشر ما لم تكن جميع المَعلمات ذات قيمة صالحة، ما يضمن عدم نشر دالة بدون إعدادات.

نقل البيانات إلى الحزمة الفرعية params

إذا كنت تستخدِم إعدادات البيئة مع functions.config، يمكنك نقل إعداداتك الحالية إلى الإعدادات المُستخدِمة للمَعلمات.

الإصدار السابق: الجيل الأول

const functions = require("firebase-functions/v1");

exports.date = functions.https.onRequest((req, res) => {
  const date = new Date();
  const formattedDate =
date.toLocaleDateString(functions.config().dateformat);

  // ...
});

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

const {onRequest} = require("firebase-functions/v2/https");
const {defineString} = require("firebase-functions/params");

const dateFormat = defineString("DATE_FORMAT");

exports.date = onRequest((req, res) => {
  const date = new Date();
  const formattedDate = date.toLocaleDateString(dateFormat.value());

  // ...
});

ضبط قيم المَعلمات

في المرة الأولى التي يتم فيها النشر، تطلب أداة Firebase CLI إدخال جميع قيم المَعلمات، وتحفظ القيم في ملف dotenv. لتصدير قيمملف ملف ‎ functions.config، يمكنك تنفيذ firebase functions:config:export.

لمزيد من الأمان، يمكنك أيضًا تحديد أنواع المَعلمات وقواعد التحقّق.

حالة خاصة: مفاتيح واجهة برمجة التطبيقات

يتم دمج وحدة params مع أداة Cloud Secret Manager التي توفّر التحكّم الدقيق في الوصول إلى القيم الحسّاسة، مثل مفاتيح واجهة برمجة التطبيقات. اطّلِع على المَعلمات السرية للحصول على مزيد من المعلومات.

الإصدار السابق: الجيل الأول

const functions = require("firebase-functions/v1");

exports.getQuote = functions.https.onRequest(async (req, res) => {
  const quote = await fetchMotivationalQuote(functions.config().apiKey);
  // ...
});

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

const {onRequest} = require("firebase-functions/v2/https");
const {defineSecret} = require("firebase-functions/params");

// Define the secret parameter
const apiKey = defineSecret("API_KEY");

exports.getQuote = onRequest(
  // make the secret available to this function
  { secrets: [apiKey] },
  async (req, res) => {
    // retrieve the value of the secret
    const quote = await fetchMotivationalQuote(apiKey.value());
    // ...
  }
);

ضبط خيارات وقت التشغيل

تغيّر إعداد خيارات وقت التشغيل بين الجيل الأول والثاني. ويضيف الجيل الثاني أيضًا قدرة جديدة على ضبط الخيارات لجميع الدوالّ.

الإصدار السابق: الجيل الأول

const functions = require("firebase-functions/v1");

exports.date = functions
  .runWith({
    // Keep 5 instances warm for this latency-critical function
    minInstances: 5,
  })
  // locate function closest to users
  .region("asia-northeast1")
  .https.onRequest((req, res) => {
    // ...
  });

exports.uppercase = functions
  // locate function closest to users and database
  .region("asia-northeast1")
  .firestore.document("my-collection/{docId}")
  .onCreate((change, context) => {
    // ...
  });

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

const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");
const {setGlobalOptions} = require("firebase-functions/v2");

// locate all functions closest to users
setGlobalOptions({ region: "asia-northeast1" });

exports.date = onRequest({
    // Keep 5 instances warm for this latency-critical function
    minInstances: 5,
  }, (req, res) => {
  // ...
});

exports.uppercase = onDocumentCreated("my-collection/{docId}", (event) => {
  /* ... */
});

استخدام المزامنة

من المزايا المهمة لدوالّ الجيل الثاني هي إمكانية استخدام مثيل واحد للدالة في تنفيذ أكثر من طلب واحد في الوقت نفسه. ويمكن أن يؤدي ذلك إلى تقليل عدد عمليات التشغيل على البارد التي يواجهها المستخدمون النهائيون بشكل كبير. يتم تلقائيًا تحديد عدد عمليات المعالجة المتزامنة على 80، ولكن يمكنك ضبطه على أي قيمة من 1 إلى 1000:

const {onRequest} = require("firebase-functions/v2/https");

exports.date = onRequest({
    // set concurrency value
    concurrency: 500
  },
  (req, res) => {
    // ...
});

يمكن أن يؤدي ضبط ميزة "المعالجة المتزامنة" إلى تحسين الأداء وخفض تكلفة الدوالّ. اطّلِع على مزيد من المعلومات حول طلبات المهام المتزامنة في السماح بطلبات المهام المتزامنة.

تدقيق استخدام المتغيّرات العامة

قد تستخدم الدوالّ من الجيل الأول التي تمّ كتابتها بدون مراعاة التزامن متغيّرات عامة يتمّ ضبطها وقراءتها عند كلّ طلب. عند تفعيل ميزة "المعالجة المتزامنة" وبدء مثيل واحد في التعامل مع طلبات متعددة في آنٍ واحد، قد يؤدي ذلك إلى ظهور أخطاء في الدالة عندما تبدأ الطلبات المتزامنة في ضبط المتغيّرات الشاملة وقراءتها في الوقت نفسه.

أثناء الترقية، يمكنك ضبط وحدة المعالجة المركزية للدالة على gcf_gen1 وضبط concurrency على 1 لاستعادة سلوك الجيل الأول:

const {onRequest} = require("firebase-functions/v2/https");

exports.date = onRequest({
    // TEMPORARY FIX: remove concurrency
    cpu: "gcf_gen1",
    concurrency: 1
  },
  (req, res) => {
    // ...
});

ومع ذلك، لا يُنصح بهذا الإجراء كحلّ طويل الأمد، لأنّه يفقد مزايا الأداء لوظائف الجيل الثاني. بدلاً من ذلك، تحقّق من استخدام المتغيّرات العموميّة في دوالّك، وأزِل هذه الإعدادات المؤقتة عندما تكون جاهزًا.

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

تمامًا كما هو الحال عند تغيير منطقة الدالة أو نوع العامل المشغِّل، عليك منح الدالة من الجيل الثاني اسمًا جديدًا ونقل الزيارات إليها تدريجيًا.

لا يمكن ترقية دالة من الجيل الأول إلى الجيل الثاني بالاسم نفسه وتشغيل firebase deploy. سيؤدي ذلك إلى ظهور الخطأ التالي:

Upgrading from GCFv1 to GCFv2 is not yet supported. Please delete your old function or wait for this feature to be ready.

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

  1. أعِد تسمية الدالة في رمز الدوال. على سبيل المثال، يمكنك إعادة تسمية resizeImage إلى resizeImageSecondGen.
  2. يمكنك نشر الدالة، لكي يتم تشغيل كلّ من الدالة الأصلية من الجيل الأول والدالة من الجيل الثاني.
    1. في حال بدء التشغيل و"قائمة المهام" وعوامل تشغيل HTTP، ابدأ بتوجيه جميع العملاء إلى الدالة من الجيل الثاني من خلال تعديل رمز العميل باسم الدالة من الجيل الثاني أو عنوان URL الخاص بها.
    2. باستخدام عوامل التفعيل في الخلفية، ستستجيب كل من وظائف الجيل الأول والجيل الثاني لكل حدث فور نشره.
  3. عند نقل جميع الزيارات، احذف الدالة من الجيل الأول باستخدام الأمر firebase functions:delete في واجهة برمجة التطبيقات من Firebase.
    1. يمكنك اختياريًا إعادة تسمية الدالة من الجيل الثاني لتتطابق مع اسم الدالة من الجيل الأول.