Cloud Tasks की मदद से, फ़ंक्शन को सूची में जोड़ें


टास्क क्यू फ़ंक्शन, Google Cloud Tasks का इस्तेमाल करते हैं. इससे आपके ऐप्लिकेशन को ऐसे टास्क को एसिंक्रोनस तरीके से चलाने में मदद मिलती है जिनमें ज़्यादा समय लगता है, ज़्यादा संसाधनों की ज़रूरत होती है या बैंडविथ सीमित होती है. ये टास्क, आपके मुख्य ऐप्लिकेशन फ़्लो के बाहर चलाए जाते हैं.

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

इस मुश्किल काम को आसान बनाने के लिए, एक टास्क क्यू फ़ंक्शन लिखा जा सकता है. यह फ़ंक्शन, scheduleTime और dispatchDeadline जैसे बुनियादी टास्क विकल्प सेट करता है. इसके बाद, फ़ंक्शन को Cloud Tasks में मौजूद क्यू को सौंप देता है. Cloud Tasks एनवायरमेंट को खास तौर पर इस तरह से डिज़ाइन किया गया है कि इस तरह के ऑपरेशन के लिए, भीड़ को असरदार तरीके से कंट्रोल किया जा सके और फिर से कोशिश करने की नीतियां लागू की जा सकें.

टास्क क्यू फ़ंक्शन के लिए, Cloud Functions for Firebase v3.20.1 और इसके बाद के वर्शन वाला Firebase SDK, Cloud Functions for Firebase v10.2.0 और इसके बाद के वर्शन के साथ काम करता है.Firebase Admin SDK

Firebase के साथ टास्क क्यू फ़ंक्शन का इस्तेमाल करने पर, Cloud Tasks प्रोसेसिंग के लिए शुल्क लग सकता है. ज़्यादा जानकारी के लिए, Cloud Tasks कीमत देखें.

टास्क की कतार वाले फ़ंक्शन बनाना

टास्क क्यू फ़ंक्शन इस्तेमाल करने के लिए, यह वर्कफ़्लो अपनाएं:

  1. Firebase SDK का इस्तेमाल करके, टास्क क्यू फ़ंक्शन लिखो.Cloud Functions
  2. एचटीटीपी अनुरोध के ज़रिए ट्रिगर करके, अपने फ़ंक्शन की जांच करें.
  3. Firebase सीएलआई की मदद से, अपने फ़ंक्शन को डिप्लॉय करें. टास्क क्यू फ़ंक्शन को पहली बार डिप्लॉय करने पर, सीएलआई Cloud Tasks में एक टास्क क्यू बनाएगा. इसमें आपके सोर्स कोड में बताए गए विकल्प (रेट लिमिट और फिर से कोशिश करना) शामिल होंगे.
  4. नई टास्क कतार में टास्क जोड़ें. अगर ज़रूरी हो, तो पैरामीटर पास करके टास्क के एक्ज़ीक्यूशन का शेड्यूल सेट अप करें. इसके लिए, Admin SDK का इस्तेमाल करके कोड लिखें और उसे Cloud Functions for Firebase पर डिप्लॉय करें.

टास्क क्यू फ़ंक्शन लिखना

इस सेक्शन में दिए गए कोड सैंपल, ऐसे ऐप्लिकेशन पर आधारित हैं जो ऐसी सेवा सेट अप करता है जो नासा की Astronomy Picture of the Day से सभी इमेज का बैक अप लेती है. शुरू करने के लिए, ज़रूरी मॉड्यूल इंपोर्ट करें:

Node.js

// Dependencies for task queue functions.
const {onTaskDispatched} = require("firebase-functions/v2/tasks");
const {onRequest, HttpsError} = require("firebase-functions/v2/https");
const {getFunctions} = require("firebase-admin/functions");
const {logger} = require("firebase-functions/v2");

// Dependencies for image backup.
const path = require("path");
const fetch = require("node-fetch");
const {initializeApp} = require("firebase-admin/app");
const {getStorage} = require("firebase-admin/storage");
const {GoogleAuth} = require("google-auth-library");

Python

# Dependencies for task queue functions.
from google.cloud import tasks_v2
import requests
from firebase_functions.options import RetryConfig, RateLimits, SupportedRegion

# Dependencies for image backup.
from datetime import datetime, timedelta
import json
import pathlib
from urllib.parse import urlparse
from firebase_admin import initialize_app, storage, functions
from firebase_functions import https_fn, tasks_fn, params
import google.auth
from google.auth.transport.requests import AuthorizedSession

टास्क की कतार से जुड़े फ़ंक्शन के लिए, onTaskDispatched या on_task_dispatched का इस्तेमाल करें. टास्क क्यू फ़ंक्शन लिखते समय, हर क्यू के लिए फिर से कोशिश करने और दर सीमित करने की सुविधा को कॉन्फ़िगर किया जा सकता है.

टास्क क्यू फ़ंक्शन कॉन्फ़िगर करना

टास्क की सूची वाले फ़ंक्शन में, कॉन्फ़िगरेशन सेटिंग का एक बेहतरीन सेट होता है. इससे टास्क की सूची की दर की सीमाओं और फिर से कोशिश करने के व्यवहार को सटीक तरीके से कंट्रोल किया जा सकता है:

Node.js

exports.backupapod = onTaskDispatched(
    {
      retryConfig: {
        maxAttempts: 5,
        minBackoffSeconds: 60,
      },
      rateLimits: {
        maxConcurrentDispatches: 6,
      },
    }, async (req) => {

Python

@tasks_fn.on_task_dispatched(retry_config=RetryConfig(max_attempts=5, min_backoff_seconds=60),
                             rate_limits=RateLimits(max_concurrent_dispatches=10))
def backupapod(req: tasks_fn.CallableRequest) -> str:
    """Grabs Astronomy Photo of the Day (APOD) using NASA's API."""
  • retryConfig.maxAttempts=5: टास्क की कतार में मौजूद हर टास्क को, अपने-आप ज़्यादा से ज़्यादा पांच बार फिर से आज़माया जाता है. इससे नेटवर्क की गड़बड़ियों या बाहरी सेवा पर निर्भर सेवा के कुछ समय के लिए बंद होने जैसी अस्थायी गड़बड़ियों को कम करने में मदद मिलती है.

  • retryConfig.minBackoffSeconds=60: हर टास्क को कम से कम 60 सेकंड के बाद फिर से आज़माया जाता है. इससे हर कोशिश के बीच एक बड़ा बफ़र मिलता है, ताकि हम पांच बार कोशिश करने की सुविधा को बहुत जल्दी खत्म न कर दें.

  • rateLimits.maxConcurrentDispatch=6: किसी भी समय ज़्यादा से ज़्यादा छह टास्क भेजे जाते हैं. इससे यह पक्का करने में मदद मिलती है कि फ़ंक्शन को लगातार अनुरोध मिलते रहें. साथ ही, इससे चालू इंस्टेंस और कोल्ड स्टार्ट की संख्या कम करने में मदद मिलती है.

टास्क की कतार से जुड़े फ़ंक्शन की जांच करना

ज़्यादातर मामलों में, टास्क क्यू फ़ंक्शन की जांच करने के लिए Cloud Functions एम्युलेटर का इस्तेमाल करना सबसे अच्छा तरीका है. टास्क कतार फ़ंक्शन के इम्यूलेशन के लिए, अपने ऐप्लिकेशन को इंस्ट्रुमेंट करने का तरीका जानने के लिए, Emulator Suite का दस्तावेज़ देखें.

इसके अलावा, task queue functions_sdk को Firebase Local Emulator Suite में सामान्य एचटीटीपी फ़ंक्शन के तौर पर दिखाया जाता है. JSON डेटा पेलोड के साथ एचटीटीपी POST अनुरोध भेजकर, टास्क फ़ंक्शन की नकल करने की सुविधा को आज़माया जा सकता है:

 # start the Local Emulator Suite
 firebase emulators:start

 # trigger the emulated task queue function
 curl \
  -X POST                                            # An HTTP POST request...
  -H "content-type: application/json" \              # ... with a JSON body
  http://localhost:$PORT/$PROJECT_ID/$REGION/$NAME \ # ... to function url
  -d '{"data": { ... some data .... }}'              # ... with JSON encoded data

टास्क क्यू फ़ंक्शन डिप्लॉय करना

Firebase सीएलआई का इस्तेमाल करके, टास्क क्यू फ़ंक्शन को डिप्लॉय करें:

$ firebase deploy --only functions:backupapod

टास्क क्यू फ़ंक्शन को पहली बार डिप्लॉय करने पर, सीएलआई Cloud Tasks में एक टास्क क्यू बनाता है. इसमें आपके सोर्स कोड में बताए गए विकल्प (दर सीमित करना और फिर से कोशिश करना) शामिल होते हैं.

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

टास्क की कतार वाले फ़ंक्शन को कतार में लगाना

टास्क क्यू फ़ंक्शन को Cloud Tasks में, भरोसेमंद सर्वर एनवायरमेंट जैसे कि Cloud Functions for Firebase से कतार में लगाया जा सकता है. इसके लिए, Node.js के लिए Firebase Admin SDK या Python के लिए Google Cloud लाइब्रेरी का इस्तेमाल किया जा सकता है. अगर आपने Admin SDK का इस्तेमाल पहले कभी नहीं किया है, तो किसी सर्वर में Firebase जोड़ना लेख पढ़ें.

सामान्य फ़्लो में, एक नया टास्क बनाया जाता है. इसके बाद, उसे Cloud Tasks में शामिल किया जाता है और टास्क के लिए कॉन्फ़िगरेशन सेट किया जाता है:

Node.js

exports.enqueuebackuptasks = onRequest(
    async (_request, response) => {
      const queue = getFunctions().taskQueue("backupapod");
      const targetUri = await getFunctionUrl("backupapod");

      const enqueues = [];
      for (let i = 0; i <= BACKUP_COUNT; i += 1) {
        const iteration = Math.floor(i / HOURLY_BATCH_SIZE);
        // Delay each batch by N * hour
        const scheduleDelaySeconds = iteration * (60 * 60);

        const backupDate = new Date(BACKUP_START_DATE);
        backupDate.setDate(BACKUP_START_DATE.getDate() + i);
        // Extract just the date portion (YYYY-MM-DD) as string.
        const date = backupDate.toISOString().substring(0, 10);
        enqueues.push(
            queue.enqueue({date}, {
              scheduleDelaySeconds,
              dispatchDeadlineSeconds: 60 * 5, // 5 minutes
              uri: targetUri,
            }),
        );
      }
      await Promise.all(enqueues);
      response.sendStatus(200);
    });

Python

@https_fn.on_request()
def enqueuebackuptasks(_: https_fn.Request) -> https_fn.Response:
    """Adds backup tasks to a Cloud Tasks queue."""
    task_queue = functions.task_queue("backupapod")
    target_uri = get_function_url("backupapod")

    for i in range(BACKUP_COUNT):
        batch = i // HOURLY_BATCH_SIZE

        # Delay each batch by N hours
        schedule_delay = timedelta(hours=batch)
        schedule_time = datetime.now() + schedule_delay

        dispatch_deadline_seconds = 60 * 5  # 5 minutes

        backup_date = BACKUP_START_DATE + timedelta(days=i)
        body = {"data": {"date": backup_date.isoformat()[:10]}}
        task_options = functions.TaskOptions(schedule_time=schedule_time,
                                             dispatch_deadline_seconds=dispatch_deadline_seconds,
                                             uri=target_uri)
        task_queue.enqueue(body, task_options)
    return https_fn.Response(status=200, response=f"Enqueued {BACKUP_COUNT} tasks")
  • इस सैंपल कोड में, टास्क को पूरा करने में लगने वाले समय को कम करने की कोशिश की गई है. इसके लिए, हर टास्क को पूरा करने में लगने वाले समय को कम किया गया है. इसका मतलब है कि हर मिनट में ~ 1 टास्क ट्रिगर होगा. ध्यान दें कि अगर आपको किसी टास्क को तय समय पर ट्रिगर करना है, तो scheduleTime (Node.js) या schedule_time (Python) का भी इस्तेमाल किया जा सकता है.Cloud Tasks

  • इस सैंपल कोड में, Cloud Tasks के लिए ज़्यादा से ज़्यादा समय सेट किया गया है. इस समय तक, Cloud Tasks किसी टास्क के पूरा होने का इंतज़ार करेगा. Cloud Tasks, टास्क को फिर से पूरा करने की कोशिश करेगा. ऐसा तब तक किया जाएगा, जब तक कि टास्क को फिर से पूरा करने के लिए कॉन्फ़िगर की गई संख्या पूरी नहीं हो जाती या यह समयसीमा खत्म नहीं हो जाती. इस सैंपल में, टास्क को पांच बार तक फिर से आज़माने के लिए, कतार को कॉन्फ़िगर किया गया है. हालांकि, अगर पूरी प्रोसेस (फिर से आज़माने की कोशिशों के साथ) में पांच मिनट से ज़्यादा समय लगता है, तो टास्क अपने-आप रद्द हो जाता है.

टारगेट यूआरआई को वापस पाना और उसे शामिल करना

Cloud Tasks, टास्क की कतार से जुड़े फ़ंक्शन के अनुरोधों की पुष्टि करने के लिए, पुष्टि करने वाले टोकन बनाता है. इसलिए, टास्क को कतार में डालते समय, आपको फ़ंक्शन का Cloud Run यूआरएल देना होगा. हमारा सुझाव है कि आप अपने फ़ंक्शन के लिए यूआरएल को प्रोग्राम के हिसाब से वापस पाएं. इसके लिए, यहां दिया गया तरीका अपनाएं:

Node.js

/**
 * Get the URL of a given v2 cloud function.
 *
 * @param {string} name the function's name
 * @param {string} location the function's location
 * @return {Promise<string>} The URL of the function
 */
async function getFunctionUrl(name, location="us-central1") {
  if (!auth) {
    auth = new GoogleAuth({
      scopes: "https://www.googleapis.com/auth/cloud-platform",
    });
  }
  const projectId = await auth.getProjectId();
  const url = "https://cloudfunctions.googleapis.com/v2beta/" +
    `projects/${projectId}/locations/${location}/functions/${name}`;

  const client = await auth.getClient();
  const res = await client.request({url});
  const uri = res.data?.serviceConfig?.uri;
  if (!uri) {
    throw new Error(`Unable to retreive uri for function at ${url}`);
  }
  return uri;
}

Python

def get_function_url(name: str, location: str = SupportedRegion.US_CENTRAL1) -> str:
    """Get the URL of a given v2 cloud function.

    Params:
        name: the function's name
        location: the function's location

    Returns: The URL of the function
    """
    credentials, project_id = google.auth.default(
        scopes=["https://www.googleapis.com/auth/cloud-platform"])
    authed_session = AuthorizedSession(credentials)
    url = ("https://cloudfunctions.googleapis.com/v2beta/" +
           f"projects/{project_id}/locations/{location}/functions/{name}")
    response = authed_session.get(url)
    data = response.json()
    function_url = data["serviceConfig"]["uri"]
    return function_url

समस्या का हल

Cloud Tasks लॉगिंग की सुविधा चालू करना

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

IAM अनुमतियां

टास्क को लाइन में लगाते समय या Cloud Tasks के टास्क कतार फ़ंक्शन को चालू करने की कोशिश करते समय, आपको PERMISSION DENIED गड़बड़ियां दिख सकती हैं. पक्का करें कि आपके प्रोजेक्ट में ये IAM बाइंडिंग मौजूद हों:

  • Cloud Tasks में टास्क जोड़ने के लिए इस्तेमाल की गई पहचान के पास, cloudtasks.tasks.create की IAM अनुमतियां होनी चाहिए.

    इस सैंपल में, यह App Engine डिफ़ॉल्ट सेवा खाता है

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member=serviceAccount:${PROJECT_ID}@appspot.gserviceaccount.com \
  --role=roles/cloudtasks.enqueuer
  • Cloud Tasks में टास्क जोड़ने के लिए इस्तेमाल की गई पहचान को, Cloud Tasks में किसी टास्क से जुड़े सेवा खाते का इस्तेमाल करने की अनुमति होनी चाहिए.

    इस सैंपल में, यह App Engine डिफ़ॉल्ट सेवा खाता है.

App Engine डिफ़ॉल्ट सेवा खाते का इस्तेमाल करने वाले व्यक्ति के तौर पर, App Engine डिफ़ॉल्ट सेवा खाता जोड़ने के निर्देशों के लिए, Google Cloud IAM दस्तावेज़ देखें.

  • टास्क क्यू फ़ंक्शन को ट्रिगर करने के लिए इस्तेमाल की गई पहचान के पास cloudfunctions.functions.invoke अनुमति होनी चाहिए.

    इस सैंपल में, यह App Engine डिफ़ॉल्ट सेवा खाता है

gcloud functions add-iam-policy-binding $FUNCTION_NAME \
  --region=us-central1 \
  --member=serviceAccount:${PROJECT_ID}@appspot.gserviceaccount.com \
  --role=roles/cloudfunctions.invoker