টিপস & কৌশল

এই নথিতে Cloud Functions ডিজাইন, বাস্তবায়ন, পরীক্ষা এবং স্থাপনের জন্য সর্বোত্তম অনুশীলনগুলি বর্ণনা করা হয়েছে।

সঠিকতা

এই বিভাগটি Cloud Functions ডিজাইন এবং বাস্তবায়নের জন্য সাধারণ সর্বোত্তম অনুশীলনগুলি বর্ণনা করে।

অযোগ্য ফাংশন লিখুন

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

ব্যাকগ্রাউন্ড অ্যাক্টিভিটি শুরু করবেন না

ব্যাকগ্রাউন্ড অ্যাক্টিভিটি হলো আপনার ফাংশনটি বন্ধ হওয়ার পরে ঘটে এমন যেকোনো কিছু। ফাংশনটি ফিরে আসার পরে বা অন্যথায় সমাপ্তির সংকেত দেওয়ার পরে একটি ফাংশন ইনভোকেশন শেষ হয়, যেমন Node.js ইভেন্ট-চালিত ফাংশনে callback আর্গুমেন্ট কল করে। গ্রেসফুল টার্মিনেশনের পরে চালানো যেকোনো কোড CPU অ্যাক্সেস করতে পারে না এবং কোনও অগ্রগতি করবে না।

এছাড়াও, যখন একই পরিবেশে পরবর্তী আমন্ত্রণ কার্যকর করা হয়, তখন আপনার ব্যাকগ্রাউন্ড অ্যাক্টিভিটি পুনরায় শুরু হয়, যা নতুন আমন্ত্রণে হস্তক্ষেপ করে। এর ফলে অপ্রত্যাশিত আচরণ এবং ত্রুটি দেখা দিতে পারে যা নির্ণয় করা কঠিন। কোনও ফাংশন বন্ধ হয়ে যাওয়ার পরে নেটওয়ার্ক অ্যাক্সেস করার ফলে সাধারণত সংযোগগুলি পুনরায় সেট করা হয় ( ECONNRESET ত্রুটি কোড)।

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

সর্বদা অস্থায়ী ফাইলগুলি মুছুন

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

গুগল ক্লাউড কনসোলের ফাংশনের তালিকায় একটি ফাংশন নির্বাচন করে এবং মেমোরি ব্যবহারের প্লট নির্বাচন করে আপনি একটি পৃথক ফাংশন দ্বারা ব্যবহৃত মেমোরি দেখতে পারেন।

যদি আপনার দীর্ঘমেয়াদী স্টোরেজ অ্যাক্সেসের প্রয়োজন হয়, তাহলে Cloud Storage বা NFS ভলিউম সহ Cloud Run ভলিউম মাউন্ট ব্যবহার করার কথা বিবেচনা করুন।

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

ফাংশন ফ্রেমওয়ার্ক

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

এটি করার জন্য, প্রাসঙ্গিক লক ফাইলে আপনার পছন্দের সংস্করণটি অন্তর্ভুক্ত করুন (উদাহরণস্বরূপ, Node.js-এর জন্য package-lock.json , অথবা Python-এর জন্য requirements.txt )।

যদি ফাংশন ফ্রেমওয়ার্ক স্পষ্টভাবে নির্ভরতা হিসাবে তালিকাভুক্ত না হয়, তাহলে এটি স্বয়ংক্রিয়ভাবে বিল্ড প্রক্রিয়ার সময় সর্বশেষ উপলব্ধ সংস্করণ ব্যবহার করে যোগ করা হবে।

যন্ত্র

এই বিভাগটি Cloud Functions বাস্তবায়ন, পরীক্ষা এবং ইন্টারঅ্যাক্ট করার জন্য সরঞ্জামগুলি কীভাবে ব্যবহার করতে হয় তার নির্দেশিকা প্রদান করে।

স্থানীয় উন্নয়ন

ফাংশন স্থাপনে কিছুটা সময় লাগে, তাই স্থানীয়ভাবে আপনার ফাংশনের কোড পরীক্ষা করা প্রায়শই দ্রুত হয়।

ফায়ারবেস ডেভেলপাররা ফায়ারবেস সিএলআই Cloud Functions এমুলেটর ব্যবহার করতে পারেন।

আরম্ভের সময় স্থাপনার সময়সীমা এড়িয়ে চলুন

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

Firebase সিএলআই-এর ডিপ্লয়মেন্টের সময় আপনার ফাংশনগুলি আবিষ্কার করার জন্য একটি ডিফল্ট টাইমআউট থাকে। যদি আপনার ফাংশনের সোর্স কোডে (মডিউল লোড করা, নেটওয়ার্ক কল করা ইত্যাদি) ইনিশিয়ালাইজেশন লজিক এই টাইমআউট অতিক্রম করে, তাহলে ডিপ্লয়মেন্ট ব্যর্থ হতে পারে।

টাইমআউট এড়াতে, নিম্নলিখিত কৌশলগুলির মধ্যে একটি ব্যবহার করুন:

স্থাপনার সময় ইনিশিয়ালাইজেশন কোড চালানো এড়াতে onInit() হুক ব্যবহার করুন। onInit() হুকের ভিতরের কোডটি কেবল তখনই চলবে যখন ফাংশনটি ক্লাউড রান ফাংশনে স্থাপন করা হবে, স্থাপনার প্রক্রিয়ার সময় নয়।

নোড.জেএস

const { onInit } = require('firebase-functions/v2/core');
const { onRequest } = require('firebase-functions/v2/https');

// Example of a slow initialization task
function slowInitialization() {
  // Simulate a long-running operation (e.g., loading a large model, network request).
  return new Promise(resolve => {
      setTimeout(() => {
          console.log("Slow initialization complete");
          resolve("Initialized Value");
      }, 20000); // Simulate a 20-second delay
  });
}
let initializedValue;

onInit(async () => {
  initializedValue = await slowInitialization();
});

exports.myFunction = onRequest((req, res) => {
  // Access the initialized value. It will be ready after the first invocation.
  res.send(`Value: ${initializedValue}`);
});

পাইথন

from firebase_functions.core import init
from firebase_functions import https_fn
import time

# Example of a slow initialization task
def _slow_initialization():
  time.sleep(20)  # Simulate a 20-second delay
  print("Slow initialization complete")
  return "Initialized Value"

_initialized_value = None

@init
def initialize():
  global _initialized_value
  _initialized_value = _slow_initialization()

@https_fn.on_request()
def my_function(req: https_fn.Request) -> https_fn.Response:
  # Access the initialized value. It will be ready after the first invocation.
  return https_fn.Response(f"Value: {_initialized_value}")

(বিকল্প) আবিষ্কারের সময়সীমা বাড়ান

যদি আপনি onInit() ব্যবহার করার জন্য আপনার কোডটি রিফ্যাক্টর করতে না পারেন, তাহলে আপনি FUNCTIONS_DISCOVERY_TIMEOUT এনভায়রনমেন্ট ভেরিয়েবল ব্যবহার করে CLI এর ডিপ্লয়মেন্ট টাইমআউট বাড়াতে পারেন:

$ export FUNCTIONS_DISCOVERY_TIMEOUT=30
$ firebase deploy --only functions

ইমেল পাঠাতে Sendgrid ব্যবহার করুন

Cloud Functions পোর্ট ২৫-এ আউটবাউন্ড সংযোগের অনুমতি দেয় না, তাই আপনি কোনও SMTP সার্ভারে অ-নিরাপদ সংযোগ তৈরি করতে পারবেন না। ইমেল পাঠানোর প্রস্তাবিত উপায় হল SendGrid এর মতো তৃতীয় পক্ষের পরিষেবা ব্যবহার করা। আপনি Google Compute Engine-এর জন্য Sending Email from an Instance টিউটোরিয়ালে ইমেল পাঠানোর অন্যান্য বিকল্পগুলি খুঁজে পেতে পারেন।

কর্মক্ষমতা

এই বিভাগটি কর্মক্ষমতা অপ্টিমাইজ করার জন্য সর্বোত্তম অনুশীলনগুলি বর্ণনা করে।

কম কনকারেন্সি এড়িয়ে চলুন

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

কনকারেন্সি বৃদ্ধি করলে প্রতি উদাহরণে একাধিক অনুরোধ পিছিয়ে দেওয়া যায়, যার ফলে লোডের স্পাইকগুলি পরিচালনা করা সহজ হয়।

নির্ভরতা বিজ্ঞতার সাথে ব্যবহার করুন

যেহেতু ফাংশনগুলি স্টেটলেস, তাই এক্সিকিউশন এনভায়রনমেন্ট প্রায়শই শুরু থেকে শুরু করা হয় (যাকে কোল্ড স্টার্ট বলা হয়)। যখন একটি কোল্ড স্টার্ট ঘটে, তখন ফাংশনের বিশ্বব্যাপী প্রেক্ষাপট মূল্যায়ন করা হয়।

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

ভবিষ্যতের আমন্ত্রণে বস্তু পুনঃব্যবহার করতে গ্লোবাল ভেরিয়েবল ব্যবহার করুন

ভবিষ্যতের ইনভোকেশনের জন্য কোনও ফাংশনের অবস্থা সংরক্ষণ করা হবে এমন কোনও গ্যারান্টি নেই। তবে, Cloud Functions প্রায়শই পূর্ববর্তী ইনভোকেশনের এক্সিকিউশন পরিবেশ পুনর্ব্যবহার করে। যদি আপনি গ্লোবাল স্কোপে একটি ভেরিয়েবল ঘোষণা করেন, তাহলে এর মান পরবর্তী ইনভোকেশনে পুনঃব্যবহার করা যেতে পারে, পুনঃগণনা না করেই।

এইভাবে আপনি প্রতিটি ফাংশন ইনভোকেশনে এমন বস্তু ক্যাশে করতে পারবেন যা পুনঃনির্মাণ করা ব্যয়বহুল হতে পারে। ফাংশন বডি থেকে গ্লোবাল স্কোপে এই ধরনের বস্তু স্থানান্তরের ফলে উল্লেখযোগ্য কর্মক্ষমতা উন্নতি হতে পারে। নিম্নলিখিত উদাহরণটি প্রতিটি ফাংশন ইনস্ট্যান্সে কেবল একবার একটি ভারী বস্তু তৈরি করে এবং প্রদত্ত ইনস্ট্যান্সে পৌঁছানো সমস্ত ফাংশন ইনভোকেশনে এটি ভাগ করে নেয়:

নোড.জেএস

console.log('Global scope');
const perInstance = heavyComputation();
const functions = require('firebase-functions');

exports.function = functions.https.onRequest((req, res) => {
  console.log('Function invocation');
  const perFunction = lightweightComputation();

  res.send(`Per instance: ${perInstance}, per function: ${perFunction}`);
});

পাইথন

import time

from firebase_functions import https_fn

# Placeholder
def heavy_computation():
  return time.time()

# Placeholder
def light_computation():
  return time.time()

# Global (instance-wide) scope
# This computation runs at instance cold-start
instance_var = heavy_computation()

@https_fn.on_request()
def scope_demo(request):

  # Per-function scope
  # This computation runs every time this function is called
  function_var = light_computation()
  return https_fn.Response(f"Instance: {instance_var}; function: {function_var}")
  

এই HTTP ফাংশনটি একটি অনুরোধ বস্তু ( flask.Request ) নেয় এবং প্রতিক্রিয়া পাঠ্য, অথবা make_response ব্যবহার করে Response বস্তুতে রূপান্তরিত করা যেতে পারে এমন যেকোনো মানের সেট ফেরত দেয়।

নেটওয়ার্ক সংযোগ, লাইব্রেরি রেফারেন্স এবং API ক্লায়েন্ট অবজেক্টগুলিকে গ্লোবাল স্কোপে ক্যাশে করা বিশেষভাবে গুরুত্বপূর্ণ। উদাহরণের জন্য নেটওয়ার্কিং অপ্টিমাইজেশন দেখুন।

ন্যূনতম সংখ্যক ইনস্ট্যান্স সেট করে ঠান্ডা লাগা কমাতে হবে

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

এই রানটাইম বিকল্পগুলি সম্পর্কে আরও তথ্যের জন্য স্কেলিং আচরণ নিয়ন্ত্রণ করুন দেখুন।

কোল্ড স্টার্ট এবং ইনিশিয়ালাইজেশন সম্পর্কে নোটস

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

তবে, গ্লোবাল ইনিশিয়ালাইজেশন কোল্ড স্টার্টের উপরও প্রভাব ফেলে। এই প্রভাব কমাতে, প্রথম অনুরোধের জন্য যা প্রয়োজন তা কেবল ইনিশিয়ালাইজ করুন, যাতে প্রথম অনুরোধের ল্যাটেন্সি যতটা সম্ভব কম থাকে।

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

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

একটি async node.js লাইব্রেরি প্রিওয়ার্ম করার উদাহরণ

Firestore সহ Node.js হল async node.js লাইব্রেরির একটি উদাহরণ। min_instances এর সুবিধা নেওয়ার জন্য, নিম্নলিখিত কোডটি লোডের সময় লোডিং এবং ইনিশিয়ালাইজেশন সম্পূর্ণ করে, মডিউল লোডিং ব্লক করে।

TLA ব্যবহার করা হয়, যার অর্থ ES6 প্রয়োজন, node.js কোডের জন্য একটি .mjs এক্সটেনশন ব্যবহার করে অথবা package.json ফাইলে type: module যোগ করে।

{
  "main": "main.js",
  "type": "module",
  "dependencies": {
    "@google-cloud/firestore": "^7.10.0",
    "@google-cloud/functions-framework": "^3.4.5"
  }
}

নোড.জেএস

import Firestore from '@google-cloud/firestore';
import * as functions from '@google-cloud/functions-framework';

const firestore = new Firestore({preferRest: true});

// Pre-warm firestore connection pool, and preload our global config
// document in cache. In order to ensure no other request comes in,
// block the module loading with a synchronous global request:
const config = await firestore.collection('collection').doc('config').get();

functions.http('fetch', (req, res) => {

// Do something with config and firestore client, which are now preloaded
// and will execute at lower latency.
});

বিশ্বব্যাপী সূচনার উদাহরণ

নোড.জেএস

const functions = require('firebase-functions');
let myCostlyVariable;

exports.function = functions.https.onRequest((req, res) => {
  doUsualWork();
  if(unlikelyCondition()){
      myCostlyVariable = myCostlyVariable || buildCostlyVariable();
  }
  res.status(200).send('OK');
});

পাইথন

from firebase_functions import https_fn

# Always initialized (at cold-start)
non_lazy_global = file_wide_computation()

# Declared at cold-start, but only initialized if/when the function executes
lazy_global = None

@https_fn.on_request()
def lazy_globals(request):

  global lazy_global, non_lazy_global

  # This value is initialized only if (and when) the function is called
  if not lazy_global:
      lazy_global = function_specific_computation()

  return https_fn.Response(f"Lazy: {lazy_global}, non-lazy: {non_lazy_global}.")
  

এই HTTP ফাংশনটি অলসভাবে শুরু করা গ্লোবাল ব্যবহার করে। এটি একটি অনুরোধ বস্তু ( flask.Request ) নেয় এবং প্রতিক্রিয়া পাঠ্য, অথবা make_response ব্যবহার করে Response বস্তুতে রূপান্তরিত করা যেতে পারে এমন যেকোনো মানের সেট ফেরত দেয়।

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

অতিরিক্ত সম্পদ

"গুগল ক্লাউড পারফরম্যান্স অ্যাটলাস" ভিডিওতে কর্মক্ষমতা অপ্টিমাইজ করার বিষয়ে আরও জানুন Cloud Functions কোল্ড বুট টাইম