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


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

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

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

'Firebase के लिए Cloud Functions' के लिए 'Firebase SDK टूल' का वर्शन 3.20.1 और इसके बाद के वर्शन, Firebase एडमिन SDK के 10.2.0 वर्शन और उसके बाद के वर्शन के साथ काम करते हैं. इससे टास्क सूची वाले फ़ंक्शन काम करते हैं.

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

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

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

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

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

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

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: एक बार में ज़्यादा से ज़्यादा 6 टास्क भेजे जाते हैं. इससे यह पक्का करने में मदद मिलती है कि बुनियादी फ़ंक्शन के लिए अनुरोधों की संख्या लगातार बनी रहे. साथ ही, ऐक्टिव इंस्टेंस की संख्या और कोल्ड स्टार्ट की संख्या कम करने में मदद मिलती है.

टास्क सूची के फ़ंक्शन की जांच करना

Firebase लोकल एम्युलेटर सुइट में टास्क की सूची के फ़ंक्शन को आसान एचटीटीपी फ़ंक्शन के तौर पर दिखाया जाता है. 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 भूमिकाएं असाइन की गई हों.

टास्क की सूची में शामिल फ़ंक्शन को सूची में जोड़ना

'Firebase के लिए Cloud Functions' जैसे भरोसेमंद सर्वर एनवायरमेंट से, टास्क सूची वाले फ़ंक्शन को Cloud Tasks में सूची में जोड़ा जा सकता है. इसके लिए, Node.js के लिए 'Firebase एडमिन SDK' या Python के लिए Google Cloud लाइब्रेरी का इस्तेमाल किया जा सकता है. अगर आपने एडमिन 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")
  • सैंपल कोड, Nवें टास्क के लिए Nवें मिनट की देरी जोड़कर, टास्क पूरे करने की कोशिश करता है. इससे ~1 टास्क/मिनट को ट्रिगर करना पड़ जाता है. ध्यान दें कि अगर आपको Cloud 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 के लॉग बंद कर दिए जाते हैं, क्योंकि आपके प्रोजेक्ट पर बड़ी संख्या में लॉग जनरेट हो सकते हैं. हमारा सुझाव है कि अपने टास्क की सूची के फ़ंक्शन को लगातार डेवलप और डीबग करने के दौरान, आप डीबग लॉग चालू करें. लॉग इन करने की सुविधा चालू करना देखें.

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