1st gen Node.js फ़ंक्शन को 2nd gen पर अपग्रेड करें

1st gen फ़ंक्शन का इस्तेमाल करने वाले ऐप्लिकेशन को, इस गाइड में दिए गए निर्देशों के मुताबिक 2nd gen पर माइग्रेट करने के बारे में सोचना चाहिए. दूसरी जनरेशन के फ़ंक्शन, Cloud Run का इस्तेमाल करके बेहतर परफ़ॉर्मेंस, बेहतर कॉन्फ़िगरेशन, बेहतर मॉनिटरिंग, और अन्य सुविधाएं देते हैं.

इस दस्तावेज़ में दिए गए उदाहरणों में, यह माना गया है कि CommonJS मॉड्यूल (require स्टाइल इंपोर्ट) के साथ JavaScript का इस्तेमाल किया जा रहा है. हालांकि, यही सिद्धांत ESM (import … from स्टाइल इंपोर्ट) और TypeScript के साथ JavaScript पर भी लागू होते हैं.

माइग्रेशन की प्रोसेस

1st gen और 2nd gen फ़ंक्शन, एक ही फ़ाइल में साथ-साथ मौजूद हो सकते हैं. इससे, कोडबेस को धीरे-धीरे माइग्रेट किया जा सकता है. हमारा सुझाव है कि एक बार में एक फ़ंक्शन माइग्रेट करें. साथ ही, आगे बढ़ने से पहले उसकी जांच और पुष्टि करें.

Firebase CLI और firebase-function के वर्शन की पुष्टि करना

पक्का करें कि कम से कम Firebase CLI का 12.00 वर्शन और firebase-functions का 4.3.0 वर्शन इस्तेमाल किया जा रहा हो. कोई भी नया वर्शन, पहली और दूसरी जनरेशन, दोनों के साथ काम करेगा.

इंपोर्ट अपडेट करना

दूसरी जनरेशन के फ़ंक्शन, firebase-functions SDK में मौजूद v2 सबपैकेज से इंपोर्ट होते हैं. 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");

ट्रिगर की परिभाषाएं अपडेट करना

चूंकि 2nd gen SDK मॉड्यूलर इंपोर्ट को प्राथमिकता देता है, इसलिए ट्रिगर की परिभाषाओं को अपडेट करके, पिछले चरण में किए गए इंपोर्ट में हुए बदलावों को दिखाएं.

कुछ ट्रिगर के लिए कॉलबैक में पास किए गए आर्ग्युमेंट बदल गए हैं. इस उदाहरण में, ध्यान दें कि onDocumentCreated कॉलबैक के आर्ग्युमेंट को एक ही event ऑब्जेक्ट में शामिल कर दिया गया है. इसके अलावा, कुछ ट्रिगर में कॉन्फ़िगरेशन की नई सुविधाएं जोड़ी गई हैं. जैसे, onRequest ट्रिगर का cors विकल्प.

पहली जनरेशन से पहले

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 डीस्ट्रक्चरिंग की मदद से, कोड को फिर से लिखने की ज़रूरत को कम करना

अगर आपके फ़ंक्शन में जटिल बॉडी हैं जो 1st gen कॉन्टेक्स्ट या provider-specific पैरामीटर (जैसे, message या snapshot) पर निर्भर करती हैं, तो 2nd gen एसडीके में मौजूद, 1st gen के साथ काम करने वाले हेल्पर का इस्तेमाल किया जा सकता है.

दूसरी जनरेशन का एसडीके, इवेंट ऑब्जेक्ट को पहली जनरेशन के सिग्नेचर से मैच करने वाले गेटर के साथ अपने-आप पैच करता है. इससे, हैंडलर सिग्नेचर में इन प्रॉपर्टी को सीधे तौर पर निकालने के लिए, JavaScript डीस्ट्रक्चरिंग का इस्तेमाल किया जा सकता है. इससे, फ़ंक्शन लॉजिक को फिर से लिखने की ज़रूरत कम हो जाती है.

Provider मैपिंग का रेफ़रंस

Provider पहली जनरेशन के आर्ग्युमेंट दूसरी जनरेशन के पैच्ड इवेंट डीस्ट्रक्चरिंग
Pub/Sub (message, context) ({ message, context }) => { ... }
Firestore (snapshot, context) ({ snapshot, context }) => { ... }
स्टोरेज (object, context) ({ object, context }) => { ... }
रियलटाइम डेटाबेस (snapshot, context) ({ snapshot, context }) => { ... }
Remote Config (version, context) ({ version, context }) => { ... }
शेड्यूलर (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 के साथ मौजूदा एनवायरमेंट कॉन्फ़िगरेशन है, तो 2nd gen में अपग्रेड करने के दौरान, इस कॉन्फ़िगरेशन को माइग्रेट करें.

functions.config API को बंद कर दिया गया है. इसे मार्च 2027 में पूरी तरह से बंद कर दिया जाएगा. इसके बाद, functions.config के साथ किए गए डिप्लॉयमेंट काम नहीं करेंगे.

डिप्लॉयमेंट में होने वाली गड़बड़ियों से बचने के लिए, Firebase CLI का इस्तेमाल करके अपने कॉन्फ़िगरेशन को Cloud Secret Manager पर माइग्रेट करें. हमारा सुझाव है कि कॉन्फ़िगरेशन को माइग्रेट करने के लिए, इस तरीके का इस्तेमाल करें. यह सबसे असरदार और सुरक्षित तरीका है.

  1. CLI की मदद से कॉन्फ़िगरेशन एक्सपोर्ट करनाFirebase

    Cloud Secret Manager में मौजूद किसी नए सीक्रेट में, अपने मौजूदा एनवायरमेंट कॉन्फ़िगरेशन को एक्सपोर्ट करने के लिए, config export कमांड का इस्तेमाल करें:

    $ 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```
    
  2. सीक्रेट बाइंड करने के लिए, फ़ंक्शन कोड अपडेट करना

    Cloud Secret Manager में मौजूद नए सीक्रेट में सेव किए गए कॉन्फ़िगरेशन का इस्तेमाल करने के लिए, अपने फ़ंक्शन सोर्स में defineJsonSecret API का इस्तेमाल करें. साथ ही, पक्का करें कि सीक्रेट, उन सभी फ़ंक्शन से बाइंड हों जिन्हें उनकी ज़रूरत है.

    पहली जनरेशन से पहले

    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;
        // ...
    });
    
  3. फ़ंक्शन डिप्लॉय करना

    बदलावों को लागू करने और सीक्रेट की अनुमतियां बाइंड करने के लिए, अपडेट किए गए फ़ंक्शन डिप्लॉय करें.

    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) => {
  /* ... */
});

डिफ़ॉल्ट सेवा खाता अपडेट करना (ज़रूरी नहीं)

पहली जनरेशन के फ़ंक्शन, Firebase API के ऐक्सेस को अनुमति देने के लिए, Google App Engine के डिफ़ॉल्ट सेवा खाते का इस्तेमाल करते हैं. वहीं, दूसरी जनरेशन के फ़ंक्शन, Compute Engine के डिफ़ॉल्ट सेवा खाते का इस्तेमाल करते हैं. इस अंतर की वजह से, 2nd gen में माइग्रेट किए गए फ़ंक्शन के लिए, अनुमतियों से जुड़ी समस्याएं हो सकती हैं. ऐसा तब होता है, जब आपने 1st gen के सेवा खाते को खास अनुमतियां दी हों. अगर आपने सेवा खाते की अनुमतियों में कोई बदलाव नहीं किया है, तो इस चरण को छोड़ा जा सकता है.

हमारा सुझाव है कि पहली जनरेशन के 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) => {
    // ...
});

कॉन्करेंसी को ट्यून करने से, परफ़ॉर्मेंस बेहतर हो सकती है और फ़ंक्शन की लागत कम हो सकती है. कॉन्करेंसी के बारे में ज़्यादा जानने के लिए, एक साथ कई अनुरोधों की अनुमति देना लेख पढ़ें.

ग्लोबल वैरिएबल के इस्तेमाल की जांच करना

पहली जनरेशन के ऐसे फ़ंक्शन जिनमें कॉन्करेंसी का इस्तेमाल नहीं किया गया है उनमें, ग्लोबल वैरिएबल का इस्तेमाल किया जा सकता है. इन वैरिएबल को हर अनुरोध पर सेट और पढ़ा जाता है. जब कॉन्करेंसी चालू होती है और एक ही इंस्टेंस, एक साथ कई अनुरोधों को हैंडल करना शुरू करता है, तो आपके फ़ंक्शन में गड़बड़ियां आ सकती हैं. ऐसा इसलिए, क्योंकि कॉन्करेंट अनुरोध, ग्लोबल वैरिएबल को एक साथ सेट और पढ़ना शुरू कर देते हैं.

अपग्रेड करते समय, अपने फ़ंक्शन के सीपीयू को 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) => {
    // ...
});

हालांकि, लंबे समय तक इस तरीके का इस्तेमाल करने का सुझाव नहीं दिया जाता. ऐसा इसलिए, क्योंकि इससे 2nd gen फ़ंक्शन की परफ़ॉर्मेंस से जुड़े फ़ायदे नहीं मिल पाते. इसके बजाय, अपने फ़ंक्शन में ग्लोबल वैरिएबल के इस्तेमाल की जांच करें. साथ ही, जब ज़रूरत न हो, तो इन अस्थायी सेटिंग को हटा दें.

ट्रैफ़िक को नई 2nd gen फ़ंक्शन पर माइग्रेट करना

ठीक उसी तरह जैसे किसी फ़ंक्शन का इलाका या ट्रिगर टाइप बदलते समय, आपको 2nd gen फ़ंक्शन को नया नाम देना होगा और धीरे-धीरे ट्रैफ़िक को उस पर माइग्रेट करना होगा.

किसी फ़ंक्शन को पहली से 2nd gen में अपग्रेड करने के लिए, उसे वही नाम देकर और firebase deploy कमांड नहीं चलाया जा सकता. ऐसा करने पर, यह गड़बड़ी दिखेगी:

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

माइग्रेशन की रणनीति, आपके फ़ंक्शन के इस्तेमाल किए जाने वाले ट्रिगर के टाइप पर निर्भर करती है.

कॉल किए जा सकने वाले, टास्क क्यू, और एचटीटीपी ट्रिगर के लिए

ये ट्रिगर, सीधे तौर पर कॉल किए जाते हैं. दूसरी जनरेशन के फ़ंक्शन का नाम नया होगा. साथ ही, एचटीटीपी ट्रिगर के लिए नया यूआरएल होगा. इसलिए, क्लाइंट को अपडेट करके ट्रैफ़िक को माइग्रेट किया जा सकता है.

  1. अपने कोड में फ़ंक्शन का नाम बदलें. उदाहरण के लिए, myCallable का नाम बदलकर myCallableV2 करें.
  2. फ़ंक्शन डिप्लॉय करें. अब पहली और दूसरी जनरेशन, दोनों के फ़ंक्शन चल रहे हैं.
  3. क्लाइंट कोड या कॉलर को अपडेट करके, नई 2nd gen फ़ंक्शन के नाम या यूआरएल पर पॉइंट करें.
  4. जब सारा ट्रैफ़िक नए फ़ंक्शन पर माइग्रेट हो जाए, तब Firebase CLI के firebase functions:delete कमांड का इस्तेमाल करके, पहली जनरेशन के फ़ंक्शन को मिटाएं.

बैकग्राउंड ट्रिगर (Pub/Sub, Cloud Firestore, Cloud Storage वगैरह) के लिए

बैकग्राउंड ट्रिगर, आपके प्रोजेक्ट में होने वाले इवेंट के जवाब में काम करते हैं. ट्रांसफ़र के दौरान किसी भी इवेंट को मिस होने से बचाने के लिए, आपको पहली और दूसरी जनरेशन के फ़ंक्शन को कुछ समय के लिए साथ-साथ चलाना होगा.

ट्रांसफ़र की अवधि के दौरान, दोनों फ़ंक्शन एक ही इवेंट पर ट्रिगर होंगे. इसका मतलब है कि आपके कारोबारी नियम, हर इवेंट के लिए दो बार चलेंगे. आगे बढ़ने से पहले, पक्का करें कि आपका फ़ंक्शन आइडमपोटेंट हो.

पहला चरण: 1st gen फ़ंक्शन के साथ, 2nd gen फ़ंक्शन जोड़ना

अपने कोड में, 1st gen फ़ंक्शन को बनाए रखें और उसी इवेंट सोर्स को सुनने वाला 2nd gen फ़ंक्शन जोड़ें.

पेशेवर सलाह: पुष्टि के लिए पास-थ्रू का इस्तेमाल करना ट्रांज़िशन के दौरान, कोड बेस में कारोबारी नियम को डुप्लीकेट होने से बचाने के लिए, या यह पुष्टि करने के लिए कि 2nd gen फ़ंक्शन, इवेंट को सही तरीके से पा रहा है, 2nd gen फ़ंक्शन को पास-थ्रू बनाएं. यह run तरीके का इस्तेमाल करके, 1st gen फ़ंक्शन को कॉल करता है.

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 कमांड चलाएं. अब दोनों फ़ंक्शन चालू हैं और एक ही इवेंट को सुन रहे हैं.

तीसरा चरण: पुष्टि करना कि दूसरी जनरेशन का फ़ंक्शन, ट्रैफ़िक पा रहा है

दोनों फ़ंक्शन के लॉग की निगरानी करें. पक्का करें कि 2nd gen फ़ंक्शन, सभी इवेंट के लिए कॉल किया जा रहा हो और कॉल सफल हो रहे हों.

चौथा चरण: पूरा लॉजिक, 2nd gen फ़ंक्शन में ट्रांसफ़र करना

जब आपको भरोसा हो जाए, तब पहली जनरेशन के फ़ंक्शन से, कारोबार के असली लॉजिक को दूसरी जनरेशन के फ़ंक्शन की बॉडी में ट्रांसफ़र करें. अगर आपने पासथ्रू तरीके का इस्तेमाल किया है, तो को कॉल करने की प्रोसेस हटाएं 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 ...
});

इस बदलाव को डिप्लॉय करें.

पांचवा चरण: 1st gen फ़ंक्शन को अनडिप्लॉय करना

अपने कोड से, 1st gen फ़ंक्शन की परिभाषा हटाएं और फिर से डिप्लॉय करें. CLI, आपको Google Cloud से 1st gen फ़ंक्शन को मिटाने के लिए कहेगा.

import { onMessagePublished } from "firebase-functions/v2/pubsub";

// --- V1 function definition REMOVED ---

// --- 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 ...
});