इस दस्तावेज़ में, डिज़ाइन करने, लागू करने, टेस्ट करने, और Cloud Functions को डिप्लॉय करने के सबसे सही तरीके बताए गए हैं.
सटीकता
इस सेक्शन में, डिज़ाइन और लागू करने के सबसे सही सामान्य तरीके बताए गए हैं Cloud Functions.
आइडेंटपोटेंट फ़ंक्शन लिखना
आपके फ़ंक्शन को एक ही नतीजे देने चाहिए, भले ही उन्हें कई बार कॉल किया जाए. इससे, अगर आपका कोड पूरा होने से पहले ही पिछली कॉल फ़ेल हो जाती है, तो आपके पास कॉल को फिर से करने का विकल्प होता है. ज़्यादा जानकारी के लिए, इवेंट-ड्रिवन फ़ंक्शन को फिर से कॉल करना लेख पढ़ें.
बैकग्राउंड में गतिविधियां शुरू न करना
बैकग्राउंड में होने वाली गतिविधि, वह गतिविधि होती है जो आपका फ़ंक्शन खत्म होने के बाद होती है.
फ़ंक्शन कॉल तब खत्म होती है, जब फ़ंक्शन कोई नतीजा देता है या पूरा होने का सिग्नल देता है. जैसे, Node.js के इवेंट-ड्रिवन फ़ंक्शन में callback आर्ग्युमेंट को कॉल करके. फ़ंक्शन के खत्म होने के बाद चलने वाले किसी भी कोड के पास सीपीयू का ऐक्सेस नहीं होता. इसलिए, वह कोई भी काम नहीं कर पाएगा.
इसके अलावा, जब उसी एनवायरमेंट में कोई दूसरी कॉल की जाती है, तो आपकी बैकग्राउंड गतिविधि फिर से शुरू हो जाती है. इससे नई कॉल में रुकावट आती है. इससे अनचाहे नतीजे और ऐसी गड़बड़ियां हो सकती हैं जिनका विश्लेषण करना मुश्किल हो. फ़ंक्शन के खत्म होने के बाद नेटवर्क को ऐक्सेस करने पर, आम तौर पर कनेक्शन रीसेट हो जाते हैं. ऐसा ECONNRESET गड़बड़ी कोड की वजह से होता है.
बैकग्राउंड में होने वाली गतिविधि का पता, अलग-अलग कॉल के लॉग में लगाया जा सकता है. इसके लिए, उस लाइन के बाद लॉग की गई किसी भी चीज़ को ढूंढें जिसमें यह बताया गया हो कि कॉल खत्म हो गई है. कभी-कभी बैकग्राउंड में होने वाली गतिविधि, कोड में गहराई से छिपी हो सकती है. खास तौर पर, जब कॉलबैक या टाइमर जैसे एसिंक्रोनस ऑपरेशन मौजूद हों. अपने कोड की समीक्षा करें, ताकि यह पक्का किया जा सके कि फ़ंक्शन खत्म होने से पहले, सभी एसिंक्रोनस ऑपरेशन पूरे हो जाएं.
अस्थायी फ़ाइलों को हमेशा मिटाना
अस्थायी डायरेक्ट्री में लोकल डिस्क स्टोरेज, इन-मेमोरी फ़ाइल सिस्टम होता है. आपके द्वारा लिखी गई फ़ाइलें, आपके फ़ंक्शन के लिए उपलब्ध मेमोरी का इस्तेमाल करती हैं. साथ ही, कभी-कभी ये फ़ाइलें, कॉल के बीच भी बनी रहती हैं. इन फ़ाइलों को साफ़ तौर पर न मिटाने पर, मेमोरी खत्म होने की गड़बड़ी हो सकती है. इसके बाद, कोल्ड स्टार्ट हो सकता है.
अगर आपको लंबे समय तक स्टोरेज का ऐक्सेस चाहिए, तो Cloud Run वॉल्यूम माउंट के साथ Cloud Storage या NFS वॉल्यूम का इस्तेमाल करें.
पाइपलाइनिंग का इस्तेमाल करके, बड़ी फ़ाइलों को प्रोसेस करते समय मेमोरी की ज़रूरत को कम किया जा सकता है. उदाहरण के लिए, Cloud Storage पर मौजूद किसी फ़ाइल को प्रोसेस करने के लिए, रीड स्ट्रीम बनाई जा सकती है. इसके बाद, इसे स्ट्रीम-आधारित प्रोसेस के ज़रिए पास किया जा सकता है. साथ ही, आउटपुट स्ट्रीम को सीधे Cloud Storage पर लिखा जा सकता है.
Functions Framework
यह पक्का करने के लिए कि सभी एनवायरमेंट में एक जैसी डिपेंडेंसी इंस्टॉल हों, हमारा सुझाव है कि आप अपने पैकेज मैनेजर में Functions Framework लाइब्रेरी शामिल करें. साथ ही, डिपेंडेंसी को Functions Framework के किसी खास वर्शन पर पिन करें.
ऐसा करने के लिए, अपनी पसंद का वर्शन, लॉक फ़ाइल में शामिल करें. जैसे, Node.js के लिए package-lock.json या Python के लिए requirements.txt.
अगर Functions Framework को डिपेंडेंसी के तौर पर साफ़ तौर पर लिस्ट नहीं किया जाता है, तो यह बिल्ड प्रोसेस के दौरान, उपलब्ध सबसे नए वर्शन का इस्तेमाल करके अपने-आप जुड़ जाएगा.
टूल
इस सेक्शन में, Cloud Functions को लागू करने, टेस्ट करने, और Cloud Functions के साथ इंटरैक्ट करने के लिए टूल इस्तेमाल करने के बारे में दिशा-निर्देश दिए गए हैं.
लोकल डेवलपमेंट
फ़ंक्शन को डिप्लॉय करने में थोड़ा समय लगता है. इसलिए, अक्सर अपने फ़ंक्शन के कोड को लोकल तौर पर टेस्ट करना ज़्यादा तेज़ होता है.
Firebase डेवलपर, Firebase CLI Cloud Functions Emulator का इस्तेमाल कर सकते हैं.इनिशलाइज़ेशन के दौरान, डिप्लॉयमेंट के टाइमआउट से बचना
अगर आपका फ़ंक्शन, टाइमआउट की गड़बड़ी के साथ डिप्लॉय नहीं हो पाता है, तो इसका मतलब है कि डिप्लॉयमेंट प्रोसेस के दौरान, आपके फ़ंक्शन के ग्लोबल स्कोप कोड को एक्ज़ीक्यूट होने में ज़्यादा समय लग रहा है.
Firebase CLI में, डिप्लॉयमेंट के दौरान आपके फ़ंक्शन को ढूंढने के लिए डिफ़ॉल्ट टाइमआउट होता है. अगर आपके फ़ंक्शन के सोर्स कोड में इनिशलाइज़ेशन लॉजिक (मॉड्यूल लोड करना, नेटवर्क कॉल करना वगैरह) इस टाइमआउट से ज़्यादा है, तो डिप्लॉयमेंट फ़ेल हो सकता है.
टाइमआउट से बचने के लिए, इनमें से कोई एक रणनीति अपनाएं:
(सुझाया गया) इनिशलाइज़ेशन को टालने के लिए, onInit() का इस्तेमाल करना
डिप्लॉयमेंट के दौरान, इनिशलाइज़ेशन कोड को चलाने से बचने के लिए, onInit() हुक का इस्तेमाल करें. onInit() हुक के अंदर मौजूद कोड, सिर्फ़ तब चलेगा, जब फ़ंक्शन को Cloud Run फ़ंक्शन पर डिप्लॉय किया जाएगा. यह डिप्लॉयमेंट प्रोसेस के दौरान नहीं चलेगा.
Node.js
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}`); });
Python
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 एनवायरमेंट वैरिएबल का इस्तेमाल करके, सीएलआई के डिप्लॉयमेंट टाइमआउट को बढ़ाया जा सकता है:
$ export FUNCTIONS_DISCOVERY_TIMEOUT=30
$ firebase deploy --only functions
ईमेल भेजने के लिए Sendgrid का इस्तेमाल करना
Cloud Functions पोर्ट 25 पर आउटबाउंड कनेक्शन की अनुमति नहीं देता. इसलिए, एसएमटीपी सर्वर से सुरक्षित कनेक्शन नहीं बनाया जा सकता. ईमेल भेजने के लिए, SendGrid जैसी तीसरे पक्ष की सेवा का इस्तेमाल करने का सुझाव दिया जाता है. Google Compute Engine के लिए, किसी इंस्टेंस से ईमेल भेजना ट्यूटोरियल में, ईमेल भेजने के अन्य विकल्प देखे जा सकते हैं.
परफ़ॉर्मेंस
इस सेक्शन में, परफ़ॉर्मेंस को ऑप्टिमाइज़ करने के सबसे सही तरीके बताए गए हैं.
कम कंकरेंसी से बचना
कोल्ड स्टार्ट में ज़्यादा समय लगता है. इसलिए, लोड को मैनेज करने के लिए, हाल ही में शुरू किए गए इंस्टेंस को फिर से इस्तेमाल करना, ऑप्टिमाइज़ेशन का एक बेहतरीन तरीका है. कंकरेंसी को सीमित करने से, मौजूदा इंस्टेंस का इस्तेमाल सीमित हो जाता है. इसलिए, कोल्ड स्टार्ट ज़्यादा होते हैं.
कंकरेंसी बढ़ाने से, हर इंस्टेंस के लिए कई अनुरोधों को टाला जा सकता है. इससे लोड के स्पाइक को मैनेज करना आसान हो जाता है.डिपेंडेंसी का इस्तेमाल सोच-समझकर करना
फ़ंक्शन स्टेटलेस होते हैं. इसलिए, इनके लिए एक्ज़ीक्यूशन एनवायरमेंट को अक्सर शुरू से ही इनिशलाइज़ किया जाता है. इसे कोल्ड स्टार्ट कहा जाता है. कोल्ड स्टार्ट होने पर, फ़ंक्शन के ग्लोबल कॉन्टेक्स्ट का आकलन किया जाता है.
अगर आपके फ़ंक्शन, मॉड्यूल इंपोर्ट करते हैं, तो उन मॉड्यूल के लोड होने में लगने वाला समय, कोल्ड स्टार्ट के दौरान कॉल की लेटेन्सी में जुड़ सकता है. डिपेंडेंसी को सही तरीके से लोड करके और उन डिपेंडेंसी को लोड न करके जिनका इस्तेमाल आपका फ़ंक्शन नहीं करता, इस लेटेन्सी को कम किया जा सकता है. साथ ही, अपने फ़ंक्शन को डिप्लॉय करने में लगने वाले समय को भी कम किया जा सकता है.
ग्लोबल वैरिएबल का इस्तेमाल करके, आने वाली कॉल में ऑब्जेक्ट को फिर से इस्तेमाल करना
इस बात की कोई गारंटी नहीं है कि फ़ंक्शन की स्थिति, आने वाली कॉल के लिए सेव रहेगी. हालांकि, Cloud Functions अक्सर पिछली कॉल के एक्ज़ीक्यूशन एनवायरमेंट को रीसाइकल करता है. अगर ग्लोबल स्कोप में कोई वैरिएबल तय किया जाता है, तो उसकी वैल्यू को, आने वाली कॉल में फिर से इस्तेमाल किया जा सकता है. इसके लिए, उसे फिर से कंप्यूट करने की ज़रूरत नहीं होती.
इस तरह, उन ऑब्जेक्ट को कैश किया जा सकता है जिन्हें हर फ़ंक्शन कॉल पर फिर से बनाना मुश्किल हो सकता है. ऐसे ऑब्जेक्ट को फ़ंक्शन बॉडी से ग्लोबल स्कोप में ले जाने से, परफ़ॉर्मेंस में काफ़ी सुधार हो सकता है. यहां दिए गए उदाहरण में, हर फ़ंक्शन इंस्टेंस के लिए सिर्फ़ एक बार हैवी ऑब्जेक्ट बनाया जाता है. साथ ही, इसे दिए गए इंस्टेंस तक पहुंचने वाली सभी फ़ंक्शन कॉल के साथ शेयर किया जाता है:
Node.js
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}`); });
Python
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}")
यह एचटीटीपी फ़ंक्शन, अनुरोध ऑब्जेक्ट (flask.Request) लेता है. साथ ही, रिस्पॉन्स टेक्स्ट या वैल्यू का कोई भी ऐसा सेट दिखाता है जिसे
Response ऑब्जेक्ट में बदला जा सकता है.
make_response.
ग्लोबल स्कोप में, नेटवर्क कनेक्शन, लाइब्रेरी रेफ़रंस, और एपीआई क्लाइंट ऑब्जेक्ट को कैश करना खास तौर पर ज़रूरी है. उदाहरण के लिए, नेटवर्क को ऑप्टिमाइज़ करना लेख पढ़ें.
इंस्टेंस की कम से कम संख्या सेट करके, कोल्ड स्टार्ट की संख्या कम करना
डिफ़ॉल्ट रूप से, Cloud Functions, आने वाले अनुरोधों की संख्या के आधार पर इंस्टेंस की संख्या को स्केल करता है. Cloud Functions को अनुरोधों को पूरा करने के लिए, इंस्टेंस की कम से कम संख्या को तैयार रखने के लिए सेट करके, इस डिफ़ॉल्ट सेटिंग को बदला जा सकता है. इंस्टेंस की कम से कम संख्या सेट करने से, आपके ऐप्लिकेशन के कोल्ड स्टार्ट की संख्या कम हो जाती है. अगर आपका ऐप्लिकेशन लेटेन्सी के लिए संवेदनशील है, तो हमारा सुझाव है कि इंस्टेंस की कम से कम संख्या सेट करें और लोड होने के समय इनिशलाइज़ेशन पूरा करें.
इन रनटाइम विकल्पों के बारे में ज़्यादा जानने के लिए, स्केलिंग के व्यवहार को कंट्रोल करना लेख पढ़ें.कोल्ड स्टार्ट और इनिशलाइज़ेशन के बारे में सूचनाएं
ग्लोबल इनिशलाइज़ेशन, लोड होने के समय होता है. इसके बिना, पहले अनुरोध को इनिशलाइज़ेशन पूरा करना होगा और मॉड्यूल लोड करने होंगे. इससे लेटेन्सी ज़्यादा होगी.
हालांकि, ग्लोबल इनिशलाइज़ेशन का असर कोल्ड स्टार्ट पर भी पड़ता है. इस असर को कम करने के लिए, सिर्फ़ पहले अनुरोध के लिए ज़रूरी चीज़ों को इनिशलाइज़ करें, ताकि पहले अनुरोध की लेटेन्सी कम से कम हो.
यह खास तौर पर तब ज़रूरी है, जब आपने लेटेन्सी के लिए संवेदनशील फ़ंक्शन के लिए, ऊपर बताए गए तरीके से इंस्टेंस की कम से कम संख्या कॉन्फ़िगर की हो. उस स्थिति में, लोड होने के समय इनिशलाइज़ेशन पूरा करने और काम के डेटा को कैश करने से यह पक्का होता है कि पहले अनुरोध को यह काम न करना पड़े. साथ ही, उसे कम लेटेन्सी के साथ पूरा किया जा सके.
अगर ग्लोबल स्कोप में वैरिएबल इनिशलाइज़ किए जाते हैं, तो भाषा के आधार पर, इनिशलाइज़ेशन में ज़्यादा समय लगने से दो तरह के नतीजे मिल सकते हैं: - कुछ भाषाओं और एसिंक लाइब्रेरी के कॉम्बिनेशन के लिए, फ़ंक्शन फ़्रेमवर्क एसिंक्रोनस तरीके से चल सकता है और तुरंत नतीजा दे सकता है. इससे कोड बैकग्राउंड में चलता रहता है. इससे सीपीयू को ऐक्सेस न कर पाने जैसी समस्याएं हो सकती हैं. सीपीयू को ऐक्सेस न कर पाना. इससे बचने के लिए, आपको मॉड्यूल इनिशलाइज़ेशन को ब्लॉक करना चाहिए. इसके बारे में नीचे बताया गया है. इससे यह भी पक्का होता है कि इनिशलाइज़ेशन पूरा होने तक, अनुरोधों को पूरा न किया जाए. - दूसरी ओर, अगर इनिशलाइज़ेशन सिंक्रोनस है, तो इनिशलाइज़ेशन में ज़्यादा समय लगने से कोल्ड स्टार्ट में ज़्यादा समय लगेगा. इससे लोड के स्पाइक के दौरान, कम कंकरेंसी वाले फ़ंक्शन के साथ समस्या हो सकती है.
एसिंक node.js लाइब्रेरी को प्रीवार्म करने का उदाहरण
Firestore के साथ Node.js, एसिंक node.js लाइब्रेरी का एक उदाहरण है. min_instances का फ़ायदा पाने के लिए, यहां दिया गया कोड, लोड होने के समय लोड करने और इनिशलाइज़ेशन को पूरा करता है. साथ ही, मॉड्यूल लोड होने को ब्लॉक करता है.
इसमें टीएलए का इस्तेमाल किया जाता है. इसका मतलब है कि 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" } }
Node.js
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. });
ग्लोबल इनिशलाइज़ेशन के उदाहरण
Node.js
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'); });
Python
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}.")
यह एचटीटीपी फ़ंक्शन, लेज़ीली-इनिशलाइज़्ड ग्लोबल का इस्तेमाल करता है. यह अनुरोध ऑब्जेक्ट
(flask.Request) लेता है. साथ ही, रिस्पॉन्स टेक्स्ट या वैल्यू का कोई भी ऐसा सेट दिखाता है जिसे
Response ऑब्जेक्ट में बदला जा सकता है
make_response.
यह खास तौर पर तब ज़रूरी है, जब एक ही फ़ाइल में कई फ़ंक्शन तय किए जाएं और अलग-अलग फ़ंक्शन, अलग-अलग वैरिएबल का इस्तेमाल करें. लेज़ी इनिशलाइज़ेशन का इस्तेमाल न करने पर, उन वैरिएबल पर संसाधन बर्बाद हो सकते हैं जिन्हें इनिशलाइज़ किया गया है, लेकिन उनका इस्तेमाल कभी नहीं किया गया.
अन्य संसाधन
"Google Cloud Performance Atlas" वीडियो Cloud Functions Cold Boot Time में, परफ़ॉर्मेंस को ऑप्टिमाइज़ करने के बारे में ज़्यादा जानें.