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


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

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

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

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

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

टास्क की सूची बनाने वाले फ़ंक्शन बनाना

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

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

टास्क सूची के फ़ंक्शन लिखें

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

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 का दस्तावेज़ देखें.

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

 # 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")
  • सैंपल कोड, टास्क को पूरा करने में लगने वाले समय को अलग-अलग करने की कोशिश करता है. इसके लिए, वह हर टास्क के लिए अलग-अलग समय तय करता है. इसका मतलब है कि एक मिनट में एक टास्क ट्रिगर हो सकता है. ध्यान दें कि अगर आपको किसी खास समय पर टास्क को ट्रिगर करना है, तो scheduleTime (Node.js) या schedule_time (Python) का भी इस्तेमाल किया जा सकता है.

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

IAM अनुमतियां

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

  • Cloud Tasks में टास्क को लाइन में लगाने के लिए इस्तेमाल की गई पहचान के पास, Cloud Tasks 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