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

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

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

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

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

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

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

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

يتم استيراد دوال الجيل الثاني من الحزمة الفرعية 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) => {
    // ...
});

يمكن أن يؤدي ضبط التزامن إلى تحسين الأداء وتقليل تكلفة الدوال. مزيد من المعلومات حول التزامن في السماح بالطلبات المتزامنة

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

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

أثناء الترقية، يمكنك ضبط وحدة المعالجة المركزية (CPU) للدالة على 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. في حالة المشغّلات القابلة للاستدعاء وTask Queue وHTTP، ابدأ بتوجيه جميع العملاء إلى دالة الجيل الثاني من خلال تعديل رمز العميل باسم دالة الجيل الثاني أو عنوان URL الخاص بها.
    2. باستخدام المشغّلات في الخلفية، ستستجيب كلّ من وظائف الجيل الأول والجيل الثاني لكل حدث فور نشرها.
  3. بعد نقل جميع الزيارات، احذف الدالة من الجيل الأول باستخدام الأمر firebase functions:delete في واجهة سطر الأوامر (CLI) الخاصة بـ Firebase.
    1. يمكنك اختياريًا إعادة تسمية دالة الجيل الثاني لتتطابق مع اسم دالة الجيل الأول.