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

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

يتم استيراد دوال الجيل الثاني من الحزمة الفرعية 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 عرض جميع قيم المعلّمات، ثم احفظ القيم في ملف 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، تأكَّد من أنّ الاستجابة لكتابة الأحداث في Firestore مرتَين، مرة عن طريق وظيفة من الجيل الأول ومرة من خلال وظيفة من الجيل الثاني، استجابة لتلك الأحداث، يترك التطبيق تطبيقك في حالة متسقة.

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