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

पहली जनरेशन के फ़ंक्शन इस्तेमाल करने वाले ऐप्लिकेशन को, दूसरी जनरेशन पर माइग्रेट करने के बारे में सोचना चाहिए. इसके लिए, इस गाइड में दिए गए निर्देशों का इस्तेमाल करें. दूसरी जनरेशन के फ़ंक्शन, Cloud Run का इस्तेमाल करते हैं, ताकि बेहतर परफ़ॉर्मेंस, बेहतर कॉन्फ़िगरेशन, बेहतर मॉनिटरिंग वगैरह की जा सके.

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

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

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

हमारा सुझाव है कि एक बार में सिर्फ़ एक फ़ंक्शन माइग्रेट करें. साथ ही, आगे बढ़ने से पहले उसकी जांच और पुष्टि कर लें.

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

पक्का करें कि आपके पास कम से कम Firebase सीएलआई वर्शन 12.00 और firebase-functions वर्शन 4.3.0 हो. इसके बाद के सभी वर्शन, 1st gen और 2nd gen के साथ काम करेंगे.

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

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

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

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

कुछ ट्रिगर के लिए, कॉलबैक को पास किए गए आर्ग्युमेंट बदल गए हैं. इस उदाहरण में ध्यान दें कि 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 कॉन्टेक्स्ट या सेवा देने वाली कंपनी के हिसाब से तय किए गए पैरामीटर (जैसे, message या snapshot) पर काफ़ी हद तक निर्भर करती हैं, तो 2nd gen SDK में शामिल, 1st gen के साथ काम करने वाले हेल्पर का इस्तेमाल किया जा सकता है.

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

सेवा देने वाली कंपनी की मैपिंग का रेफ़रंस

सेवा देने वाली कंपनी पहली जनरेशन के तर्क दूसरी जनरेशन का पैच किया गया इवेंट डिस्ट्रक्चरिंग
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 }) => { ... }

पहले (1st gen):

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

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

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 का इस्तेमाल करके किए गए डिप्लॉयमेंट पूरे नहीं हो पाएंगे.

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

  1. 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 एपीआई को ऐक्सेस करने की अनुमति देने के लिए 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 से 1,000 के बीच की किसी भी संख्या पर सेट किया जा सकता है:

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's firebase functions:delete कमांड का इस्तेमाल करके, पहली जनरेशन के फ़ंक्शन को मिटा दें.

बैकग्राउंड ट्रिगर माइग्रेट करना

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

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

  1. पहली जनरेशन के फ़ंक्शन के साथ-साथ दूसरी जनरेशन का फ़ंक्शन जोड़ें. इसके लिए, अपने कोड में पहली जनरेशन के मौजूदा फ़ंक्शन को रखें और दूसरी जनरेशन के फ़ंक्शन को उसी इवेंट सोर्स से जोड़ें.

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

  3. पुष्टि करें कि 2nd gen फ़ंक्शन को ट्रैफ़िक मिल रहा है. दोनों फ़ंक्शन के लॉग मॉनिटर करें. पक्का करें कि सभी इवेंट के लिए 2nd gen फ़ंक्शन चालू हो और कॉल किए जा रहे हों.

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

    इस बदलाव को लागू करें.

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