على التطبيقات التي تستخدم دوال الجيل الأول أن تفكر في الانتقال إلى الجيل الثاني باستخدام التعليمات الواردة في هذا الدليل. تستخدم دوال الجيل الثاني Cloud Run لتوفير أداء أفضل وإعدادات أفضل ومراقبة أفضل والمزيد.
تفترض الأمثلة الواردة في هذا المستند أنّك تستخدم JavaScript مع وحدات CommonJS (عمليات استيراد بنمط require)، ولكن تنطبق المبادئ نفسها على JavaScript مع ESM (عمليات استيراد بنمط import … from) وTypeScript.
عملية نقل البيانات
يمكن أن تتواجد دوال الجيل الأول والجيل الثاني جنبًا إلى جنب في ملف المصدر نفسه. يتيح لك ذلك نقل قاعدة الرموز البرمجية جزءًا تلو الآخر، عندما تكون مستعدًا. يُرجى العِلم أنّ هذا المزج بين الحِزم لا يعمل ضمن دالة واحدة منفصلة.
ننصحك بنقل دالة واحدة في كل مرة، وإجراء الاختبار والتحقّق قبل المتابعة.
التحقّق من إصدارَي واجهة سطر الأوامر (CLI) في Firebase وfirebase-functions
تأكَّد من استخدام الإصدار 12.00 من واجهة سطر الأوامر (CLI) في "Firebase" على الأقل والإصدار 4.3.0 من "firebase-functions". سيتوافق أي إصدار أحدث مع الجيل الثاني
والجيل الأول.
تعديل عمليات الاستيراد
يتم استيراد دوال الجيل الثاني من الحزمة الفرعية v2 في حزمة تطوير البرامج (SDK) لـ firebase-functions. يُعدّ مسار الاستيراد المختلف هذا هو كل ما تحتاجه واجهة سطر الأوامر (CLI) في Firebase لتحديد ما إذا كان سيتم نشر رمز الدالة كدالة من الجيل الأول أو الثاني.
الحزمة الفرعية 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) => {
/* ... */
});
تقليل جهود إعادة الكتابة باستخدام تفكيك JavaScript
إذا كانت الدوالّ تحتوي على نصوص برمجية معقّدة تعتمد بشكل كبير على سياق الجيل الأول أو
المَعلمات الخاصة بمقدّم الخدمة (مثل message أو snapshot)، يمكنك استخدام أدوات المساعدة في التوافق مع الجيل الأول
المضمّنة في حزمة تطوير البرامج (SDK) للجيل الثاني.
تُصلح حزمة تطوير البرامج (SDK) من الجيل الثاني تلقائيًا كائن الحدث باستخدام دوال getter التي تتطابق مع توقيعات الجيل الأول. يتيح لك ذلك استخدام تفكيك JavaScript لاستخراج هذه السمات مباشرةً في توقيع المعالج، ما يقلّل من الحاجة إلى إعادة كتابة منطق الدالة.
مرجع ربط مقدّمي الخدمات
| مقدّم الخدمة | وسيطات الجيل الأول | 2nd gen Patched Event Destructuring |
| Pub/Sub | (message, context)
|
({ message, context }) => { ... }
|
| Cloud Firestore | (snapshot, context)
|
({ snapshot, context }) => { ... }
|
| Cloud Storage | (object, context)
|
({ object, context }) => { ... }
|
| Realtime Database | (snapshot, context)
|
({ snapshot, context }) => { ... }
|
| Remote Config | (version, context)
|
({ version, context }) => { ... }
|
| Cloud Scheduler | (context)
|
({ context }) => { ... }
|
| قائمة انتظار المهام | (data, context)
|
({ data, context }) => { ... }
|
في السابق (الجيل الأول):
export const myPubSubV1 = functions.pubsub.topic("my-topic").onPublish((message, context) => {
const data = message.json;
const eventId = context.eventId;
// ... rest of the logic
});
البديل الجديد (الجيل الثاني مع التفكيك):
import { onMessagePublished } from "firebase-functions/v2/pubsub";
export const myPubSubV2 = onMessagePublished("my-topic", ({ message, context }) => {
// No need to change the function body!
const data = message.json; // Uses v1 Message wrapper
const eventId = context.eventId; // Uses v1 EventContext map
// ... rest of the logic
});
استخدام الإعدادات المستندة إلى مَعلمات
لا تتيح دوال الجيل الثاني استخدام functions.config، بل تستخدم واجهة أكثر أمانًا لتعريف مَعلمات الضبط بشكل تعريفي داخل قاعدة الرموز البرمجية.
باستخدام وحدة params الجديدة، تحظر واجهة سطر الأوامر (CLI) عملية النشر ما لم تكن جميع المَعلمات
تحتوي على قيمة صالحة، ما يضمن عدم نشر دالة بدون
الإعدادات اللازمة.
قبل: الجيل الأول
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());
// ...
}
);
إذا كانت لديك إعدادات بيئة حالية باستخدام functions.config، عليك نقل
هذه الإعدادات كجزء من عملية الترقية إلى الجيل الثاني.
تم إيقاف واجهة برمجة التطبيقات functions.config نهائيًا، وسيتم إيقافها نهائيًا في مارس 2027.
بعد ذلك التاريخ، ستتعذّر عمليات النشر باستخدام functions.config.
لتجنُّب حدوث أخطاء في عملية النشر، عليك نقل الإعدادات إلى Cloud Secret Manager باستخدام واجهة سطر الأوامر Firebase. ننصح بشدة باتّباع هذه الطريقة لأنّها الأكثر فعالية وأمانًا لنقل الإعدادات.
تصدير الإعدادات باستخدام واجهة سطر الأوامر في Firebase
استخدِم الأمر
config exportلتصدير إعدادات البيئة الحالية إلى رمز سرّي جديد في Cloud Secret Manager:$ firebase functions:config:export i This command retrieves your Runtime Config values (accessed via functions.config()) and exports them as a Secret Manager secret. i Fetching your existing functions.config() from your project... ✔ Fetched your existing functions.config(). i Configuration to be exported: ⚠ This may contain sensitive data. Do not share this output. { ... } ✔ What would you like to name the new secret for your configuration? RUNTIME_CONFIG ✔ Created new secret version projects/project/secrets/RUNTIME_CONFIG/versions/1```تعديل رمز الدالة لربط الرموز السرية
لاستخدام الإعدادات المخزَّنة في البيانات السرية الجديدة في Cloud Secret Manager، استخدِم واجهة برمجة التطبيقات
defineJsonSecretفي مصدر الدالة. تأكَّد أيضًا من ربط البيانات السرية بجميع الدوال التي تحتاج إليها.قبل
const functions = require("firebase-functions/v1"); exports.myFunction = functions.https.onRequest((req, res) => { const apiKey = functions.config().someapi.key; // ... });بعد
const { onRequest } = require("firebase-functions/v2/https"); const { defineJsonSecret } = require("firebase-functions/params"); const config = defineJsonSecret("RUNTIME_CONFIG"); exports.myFunction = onRequest( // Bind secret to your function { secrets: [config] }, (req, res) => { // Access secret values via .value() const apiKey = config.value().someapi.key; // ... });نشر الدوال
انشر الدوال المعدَّلة لتطبيق التغييرات وربط أذونات البيانات السرية.
firebase deploy --only functions:<your-function-name>
ضبط خيارات بيئة التشغيل
تغيّرت إعدادات خيارات وقت التشغيل بين الجيلَين الأول والثاني. يضيف الجيل الثاني أيضًا إمكانية جديدة لضبط الخيارات لجميع الدوال.
قبل: الجيل الأول
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) => {
/* ... */
});
تعديل حساب الخدمة التلقائي (اختياري)
تستخدم دوال الجيل الأول حساب الخدمة التلقائي "Google App Engine" للسماح بالوصول إلى واجهات برمجة تطبيقات "Firebase"، بينما تستخدم دوال الجيل الثاني حساب الخدمة التلقائي "Compute Engine". يمكن أن يؤدي هذا الاختلاف إلى حدوث مشاكل في الأذونات للدوال التي تم نقلها إلى الجيل الثاني في الحالات التي منحت فيها أذونات خاصة لحساب خدمة الجيل الأول. إذا لم تكن قد غيّرت أي أذونات لحساب الخدمة، يمكنك تخطّي هذه الخطوة.
الحلّ المقترَح هو تعيين حساب الخدمة التلقائي الحالي من الجيل الأول App Engine
بشكل صريح للوظائف التي تريد نقلها إلى الجيل الثاني،
مع إلغاء الإعداد التلقائي للجيل الثاني. ويمكنك إجراء ذلك من خلال التأكّد من أنّ كل دالة تم نقلها
تضبط القيمة الصحيحة لـ serviceAccountEmail:
const {onRequest} = require("firebase-functions/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");
const {setGlobalOptions} = require("firebase-functions");
// Use the App Engine default service account for all functions
setGlobalOptions({serviceAccountEmail: '<my-project-number>@<wbr>appspot.gserviceaccount.com'});
// Now I use the App Engine default service account.
exports.date = onRequest({cors: true}, (req, res) => {
// ...
});
// I do too!
exports.uppercase = onDocumentCreated("my-collection/{docId}", (event) => {
// ...
});
يمكنك بدلاً من ذلك التأكّد من تعديل تفاصيل حساب الخدمة لتتطابق مع جميع الأذونات اللازمة في كل من حساب الخدمة التلقائي App Engine (للجيل الأول) وحساب الخدمة التلقائي Compute Engine (للجيل الثاني).
استخدام التزامن
من المزايا المهمة للجيل الثاني من الدوال قدرة مثيل دالة واحدة على خدمة أكثر من طلب في وقت واحد. يمكن أن يؤدي ذلك إلى تقليل عدد عمليات التشغيل على البارد التي يواجهها المستخدمون النهائيون بشكل كبير. يتم ضبط التزامن تلقائيًا على 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.
تعتمد استراتيجية نقل البيانات على نوع المشغّل الذي تستخدمه الدالة.
نقل المشغّلات القابلة للاستدعاء وقائمة انتظار المهام وHTTP
هذه المشغّلات هي عمليات استدعاء مباشرة. بما أنّ دالة الجيل الثاني ستحمل اسمًا جديدًا (وعنوان URL جديدًا لمشغّلات HTTP)، يمكنك نقل عدد الزيارات من خلال تعديل البرامج.
- أعِد تسمية الدالة في الرمز البرمجي (على سبيل المثال، أعِد تسمية
myCallableإلىmyCallableV2). - انشر الدالة. يتم الآن تشغيل كل من دوال الجيل الأول والجيل الثاني.
- عدِّل رمز العميل أو المتصل للإشارة إلى اسم الدالة الجديدة من الجيل الثاني أو عنوان URL الخاص بها.
- بعد نقل كل الزيارات إلى الدالة الجديدة، احذف دالة الجيل الأول باستخدام الأمر Firebase في واجهة سطر الأوامر (CLI)
firebase functions:delete.
نقل المشغّلات في الخلفية
تستجيب المشغّلات في الخلفية (مثل مشغّلات Pub/Sub وCloud Firestore وCloud Storage) للأحداث في مشروعك. لتجنُّب فقدان أي أحداث أثناء عملية النقل، عليك تشغيل كل من دوال الجيل الأول والجيل الثاني مؤقتًا جنبًا إلى جنب.
خلال الفترة الانتقالية، سيتم تفعيل كلتا الدالتَين عند وقوع الحدث نفسه. وهذا يعني أنّ منطق النشاط التجاري سيتم تشغيله مرّتين لكل حدث. تأكَّد من أنّ الدالة متكررة قبل المتابعة.
أضِف دالة الجيل الثاني إلى جانب دالة الجيل الأول، مع الاحتفاظ بدالة الجيل الأول الحالية في الرمز البرمجي، وأضِف دالة الجيل الثاني التي تستمع إلى مصدر الحدث نفسه.
import * as functions from "firebase-functions/v1"; import { onMessagePublished } from "firebase-functions/v2/pubsub"; // --- Existing 1st gen function --- export const myPubSub = functions.pubsub.topic("my-topic").onPublish((message, context) => { console.log("V1 handler running for event:", context.eventId); // ... existing v1 function logic ... }); // --- New v2 passthrough function --- export const myPubSubV2 = onMessagePublished("my-topic", async ({ message, context }) => { console.log("v2 handler triggering V1 for event:", context.eventId); // Call the v1 function's handler await myPubSub.run(message, context); });شغِّل
firebase deploy. كلتا الدالتين نشطتان الآن وتستمعان إلى الأحداث نفسها.تأكَّد من أنّ دالة الجيل الثاني تتلقّى عدد الزيارات. راقِب السجلّات لكلتا الدالتَين. تأكَّد من استدعاء دالة الجيل الثاني لجميع الأحداث ومن نجاح الطلبات.
بعد التأكّد من أنّ الدالة تعمل بشكل صحيح، يمكنك نقل منطق النشاط التجاري الفعلي من دالة الجيل الأول إلى نص دالة الجيل الثاني. إذا استخدمت طريقة النقل، عليك إزالة الاستدعاء إلى
myPubSub.run().import * as functions from "firebase-functions/v1"; import { onMessagePublished } from "firebase-functions/v2/pubsub"; // --- Existing v1 function (to be removed next) --- export const myPubSub = functions.pubsub.topic("my-topic").onPublish((message, context) => { console.log("v1 handler running for event:", context.eventId); // ... existing v1 function logic ... }); // --- New v2 function with full logic --- export const myPubSubV2 = onMessagePublished("my-topic", ({ message, context }) => { console.log("v2 handler running for event:", context.eventId); // ... existing v1 function logic WAS MOVED HERE ... });انشر هذا التغيير.
أزِل تعريف دالة الجيل الأول من الرمز البرمجي وأعِد نشرها. ستطلب منك واجهة سطر الأوامر حذف دالة الجيل الأول من Google Cloud.