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

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

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

عملية الهجرة

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

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

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

تحديث الواردات

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

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

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

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

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

// 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");

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 الجديدة، تمنع واجهة سطر الأوامر (CLI) النشر ما لم تكن جميع المعلمات ذات قيمة صالحة، مما يضمن عدم نشر الوظيفة بتكوين مفقود.

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

إذا كنت تستخدم تكوين البيئة مع functions.config ، فيمكنك ترحيل التكوين الموجود لديك إلى التكوين ذو المعلمات .

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

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

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. لتصدير قيم jobs.config، قم بتشغيل firebase functions:config:export .

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

حالة خاصة: مفاتيح API

تتكامل وحدة params مع Cloud Secret Manager، الذي يوفر تحكمًا دقيقًا في الوصول إلى القيم الحساسة مثل مفاتيح API. راجع المعلمات السرية لمزيد من المعلومات.

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

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

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");

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 .
    1. بشكل اختياري، قم بإعادة تسمية وظيفة الجيل الثاني لمطابقة اسم وظيفة الجيل الأول.