1st gen Node.js ফাংশনগুলিকে 2nd gen-এ আপগ্রেড করুন৷

যেসব অ্যাপ প্রথম প্রজন্মের ফাংশন ব্যবহার করছে, তাদের এই গাইডের নির্দেশনা অনুসরণ করে দ্বিতীয় প্রজন্মে স্থানান্তরিত হওয়ার কথা বিবেচনা করা উচিত। দ্বিতীয় প্রজন্মের ফাংশনগুলো উন্নততর পারফরম্যান্স, উন্নত কনফিগারেশন, উন্নত মনিটরিং এবং আরও অনেক কিছু প্রদানের জন্য ক্লাউড রান ব্যবহার করে।

এই পৃষ্ঠার উদাহরণগুলিতে ধরে নেওয়া হয়েছে যে আপনি CommonJS মডিউল ( require style imports) সহ জাভাস্ক্রিপ্ট ব্যবহার করছেন, কিন্তু একই নীতিগুলি ESM ( import … from style imports) সহ জাভাস্ক্রিপ্ট এবং টাইপস্ক্রিপ্টের ক্ষেত্রেও প্রযোজ্য।

অভিবাসন প্রক্রিয়া

প্রথম এবং দ্বিতীয় প্রজন্মের ফাংশনগুলো একই ফাইলে পাশাপাশি থাকতে পারে। এর ফলে, আপনি প্রস্তুত হলে ধাপে ধাপে সহজেই মাইগ্রেট করতে পারবেন। আমরা পরামর্শ দিই যে, একবারে একটি করে ফাংশন মাইগ্রেট করুন এবং পরবর্তী ধাপে যাওয়ার আগে পরীক্ষা ও যাচাই করে নিন।

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

ট্রিগার সংজ্ঞা আপডেট করুন

যেহেতু ২য় প্রজন্মের 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) => {
  /* ... */
});

প্যারামিটারযুক্ত কনফিগারেশন ব্যবহার করুন

দ্বিতীয় প্রজন্মের ফাংশনগুলো 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 API-টি অপ্রচলিত হওয়ায় মার্চ ২০২৭-এ এটি বন্ধ করে দেওয়া হবে। উক্ত তারিখের পর, functions.config সহ ডেপ্লয়মেন্টগুলো ব্যর্থ হবে।

ডেপ্লয়মেন্ট ব্যর্থতা এড়াতে, Firebase CLI ব্যবহার করে আপনার কনফিগারেশন Cloud Secret Manager-এ মাইগ্রেট করুন। আপনার কনফিগারেশন মাইগ্রেট করার সবচেয়ে কার্যকর এবং নিরাপদ উপায় হিসেবে এটি জোরালোভাবে সুপারিশ করা হয়।

  1. Firebase CLI দিয়ে কনফিগারেশন এক্সপোর্ট করুন

    আপনার বিদ্যমান এনভায়রনমেন্ট কনফিগকে ক্লাউড সিক্রেট ম্যানেজারের একটি নতুন সিক্রেটে এক্সপোর্ট করতে 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. সিক্রেট বাইন্ড করতে ফাংশন কোড আপডেট করুন

    ক্লাউড সিক্রেট ম্যানেজারে নতুন সিক্রেটে সংরক্ষিত কনফিগারেশন ব্যবহার করতে, আপনার ফাংশন সোর্সে 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) => {
  /* ... */
});

ডিফল্ট পরিষেবা অ্যাকাউন্ট আপডেট করুন (ঐচ্ছিক)

যেখানে প্রথম প্রজন্মের ফাংশনগুলো ফায়ারবেস এপিআই-তে অ্যাক্সেস অনুমোদনের জন্য গুগল অ্যাপ ইঞ্জিনের ডিফল্ট সার্ভিস অ্যাকাউন্ট ব্যবহার করে, সেখানে দ্বিতীয় প্রজন্মের ফাংশনগুলো কম্পিউট ইঞ্জিনের ডিফল্ট সার্ভিস অ্যাকাউন্ট ব্যবহার করে। এই পার্থক্যের কারণে, যদি আপনি প্রথম প্রজন্মের সার্ভিস অ্যাকাউন্টকে বিশেষ অনুমতি দিয়ে থাকেন, তবে দ্বিতীয় প্রজন্মে স্থানান্তরিত ফাংশনগুলোর জন্য অনুমতি সংক্রান্ত সমস্যা দেখা দিতে পারে। যদি আপনি কোনো সার্ভিস অ্যাকাউন্টের অনুমতি পরিবর্তন না করে থাকেন, তবে আপনি এই ধাপটি এড়িয়ে যেতে পারেন।

প্রস্তাবিত সমাধান হলো, যে ফাংশনগুলোকে আপনি ২য় প্রজন্মে স্থানান্তর করতে চান, সেগুলোতে ২য় প্রজন্মের ডিফল্টকে ওভাররাইড করে বিদ্যমান ১ম প্রজন্মের অ্যাপ ইঞ্জিনের ডিফল্ট সার্ভিস অ্যাকাউন্টটি স্পষ্টভাবে নির্ধারণ করে দেওয়া। এটি করার জন্য, আপনাকে নিশ্চিত করতে হবে যে স্থানান্তরিত প্রতিটি ফাংশন 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) => {
  // ...
});

বিকল্পভাবে, আপনি অ্যাপ ইঞ্জিন ডিফল্ট সার্ভিস অ্যাকাউন্ট (১ম জেনারেশনের জন্য) এবং কম্পিউট ইঞ্জিন ডিফল্ট সার্ভিস অ্যাকাউন্ট (২য় জেনারেশনের জন্য) উভয়েরই প্রয়োজনীয় সমস্ত অনুমতির সাথে মিলিয়ে সার্ভিস অ্যাকাউন্টের বিবরণ পরিবর্তন করে নিতে পারেন।

কনকারেন্সি ব্যবহার করুন

দ্বিতীয় প্রজন্মের ফাংশনগুলোর একটি উল্লেখযোগ্য সুবিধা হলো, একটিমাত্র ফাংশন ইনস্ট্যান্স একই সাথে একাধিক অনুরোধ সম্পাদন করতে পারে। এর ফলে ব্যবহারকারীদের সম্মুখীন হওয়া কোল্ড স্টার্টের সংখ্যা ব্যাপকভাবে কমে যেতে পারে। ডিফল্টরূপে, কনকারেন্সি ৮০-তে সেট করা থাকে, কিন্তু আপনি এটিকে ১ থেকে ১০০০-এর মধ্যে যেকোনো মানে সেট করতে পারেন।

const {onRequest} = require("firebase-functions/v2/https");

exports.date = onRequest({
    // set concurrency value
    concurrency: 500
  },
  (req, res) => {
    // ...
});

কনকারেন্সি টিউনিং ফাংশনের পারফরম্যান্স উন্নত করতে এবং খরচ কমাতে পারে। ‘Allow concurrent requests’- এ কনকারেন্সি সম্পর্কে আরও জানুন।

গ্লোবাল ভেরিয়েবলের ব্যবহার নিরীক্ষা করুন

কনকারেন্সি মাথায় না রেখে লেখা প্রথম প্রজন্মের ফাংশনগুলোতে এমন গ্লোবাল ভেরিয়েবল ব্যবহৃত হতে পারে, যা প্রতিটি রিকোয়েস্টের সাথে সেট ও রিড করা হয়। যখন কনকারেন্সি চালু করা হয় এবং একটিমাত্র ইনস্ট্যান্স একসাথে একাধিক রিকোয়েস্ট হ্যান্ডেল করতে শুরু করে, তখন এটি আপনার ফাংশনে বাগ তৈরি করতে পারে, কারণ কনকারেন্ট রিকোয়েস্টগুলো একই সাথে গ্লোবাল ভেরিয়েবল সেট ও রিড করতে থাকে।

আপগ্রেড করার সময়, প্রথম প্রজন্মের আচরণ পুনরুদ্ধার করতে আপনি আপনার ফাংশনের 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.

এই ধাপগুলো অনুসরণ করার আগে, প্রথমে নিশ্চিত করুন যে আপনার ফাংশনটি আইডম্পোটেন্ট (idempotent) , কারণ পরিবর্তনের সময় আপনার ফাংশনের নতুন এবং পুরানো উভয় সংস্করণই একই সাথে চালু থাকবে। উদাহরণস্বরূপ, যদি আপনার একটি প্রথম প্রজন্মের (1st gen) ফাংশন থাকে যা ফায়ারস্টোরে (Firestore) রাইট (write) ইভেন্টে সাড়া দেয়, তবে নিশ্চিত করুন যে সেই ইভেন্টগুলোর প্রতিক্রিয়ায় একবার প্রথম প্রজন্মের ফাংশন দ্বারা এবং একবার দ্বিতীয় প্রজন্মের ফাংশন দ্বারা দুইবার রাইট সাড়া দিলেও আপনার অ্যাপটি একটি সামঞ্জস্যপূর্ণ অবস্থায় থাকে।

  1. আপনার ফাংশন কোডে ফাংশনটির নাম পরিবর্তন করুন। উদাহরণস্বরূপ, resizeImage কে resizeImageSecondGen এ পরিবর্তন করুন।
  2. ফাংশনটি ডিপ্লয় করুন, যাতে মূল প্রথম প্রজন্মের ফাংশন এবং দ্বিতীয় প্রজন্মের ফাংশন উভয়ই চালু থাকে।
    1. কলযোগ্য, টাস্ক কিউ এবং HTTP ট্রিগারের ক্ষেত্রে, ক্লায়েন্ট কোডে ২য় প্রজন্মের ফাংশনের নাম বা URL আপডেট করে সমস্ত ক্লায়েন্টকে সেই ফাংশনের দিকে নির্দেশ করা শুরু করুন।
    2. ব্যাকগ্রাউন্ড ট্রিগারের সাহায্যে, প্রথম ও দ্বিতীয় প্রজন্মের উভয় ফাংশনই ডেপ্লয় হওয়ার সাথে সাথে প্রতিটি ইভেন্টে সাড়া দেবে।
  3. সমস্ত ট্র্যাফিক স্থানান্তরিত হয়ে গেলে, firebase CLI-এর firebase functions:delete কমান্ড ব্যবহার করে প্রথম প্রজন্মের ফাংশনটি মুছে ফেলুন।
    1. ঐচ্ছিকভাবে, দ্বিতীয় প্রজন্মের ফাংশনটির নাম পরিবর্তন করে প্রথম প্রজন্মের ফাংশনটির নামের সাথে মিলিয়ে দিন।