Python 2 App Engine Cloud NDB & को माइग्रेट करना Python 3 और Cloud Datastore (मॉड्यूल 9) पर Cloud Tasks ऐप्लिकेशन इस्तेमाल करना

1. खास जानकारी

कोडलैब के बिना सर्वर वाले माइग्रेशन स्टेशन की सीरीज़ (अपने हिसाब से इस्तेमाल किए जाने वाले ट्यूटोरियल) और मिलते-जुलते वीडियो का मकसद, Google Cloud के बिना सर्वर वाले डेवलपर को अपने ऐप्लिकेशन को आधुनिक बनाने में मदद करना है. ऐसा करने के लिए, उन्हें लेगसी सेवाओं का इस्तेमाल बंद करना होगा. ऐसा करने के लिए, उन्हें एक या एक से ज़्यादा माइग्रेशन में मदद मिलेगी. ऐसा करने से, आपके ऐप्लिकेशन ज़्यादा पोर्टेबल बन जाते हैं. साथ ही, आपको ज़्यादा विकल्प और सुविधाएं भी मिलती हैं. इससे, क्लाउड प्रॉडक्ट की बड़ी रेंज को इंटिग्रेट किया जा सकता है और उन्हें ऐक्सेस किया जा सकता है. साथ ही, नई भाषाओं में रिलीज़ किए जाने वाले ऐप्लिकेशन पर आसानी से अपग्रेड किया जा सकता है. शुरुआत में App Engine (स्टैंडर्ड एनवायरमेंट) वाले डेवलपर पर ध्यान दिया जाता है. हालांकि, यह सीरीज़ इतनी बड़ी है कि इसमें Cloud Functions और Cloud Run जैसे बिना सर्वर वाले प्लैटफ़ॉर्म या लागू होने पर, उन्हें शामिल किया जा सकता है.

इस कोडलैब का मकसद, मॉड्यूल 8 सैंपल ऐप्लिकेशन को Python 3 में पोर्ट करना और Datastore (Datastore मोड में Cloud Firestore) के ऐक्सेस को बदलना है. साथ ही, Cloud NDB से, खास Cloud Datastore क्लाइंट लाइब्रेरी पर जाना और Cloud Tasks क्लाइंट लाइब्रेरी के नए वर्शन पर अपग्रेड करना है.

हमने मॉड्यूल 7 में, पुश टास्क के लिए टास्क सूची के इस्तेमाल को जोड़ा. इसके बाद, हमने मॉड्यूल 8 में इस इस्तेमाल को Cloud Tasks पर माइग्रेट कर दिया. मॉड्यूल 9 में, हमने Python 3 और Cloud Datastore के साथ काम करना जारी रखा है. पुल बनाने के लिए, टास्क की सूची का इस्तेमाल करने वाले लोग, Cloud Pub/Sub पर माइग्रेट हो जाएंगे. इसके लिए, उन्हें मॉड्यूल 18-19 के हिसाब से पढ़ना चाहिए.

आपको इनके बारे में जानकारी मिलेगी

  • मॉड्यूल 8 सैंपल ऐप्लिकेशन को Python 3 में पोर्ट करें
  • Datastore के ऐक्सेस को Cloud NDB से Cloud Datastore क्लाइंट लाइब्रेरी पर स्विच करें
  • Cloud Tasks क्लाइंट लाइब्रेरी के सबसे नए वर्शन पर अपग्रेड करें

आपको इनकी ज़रूरत होगी

सर्वे

इस ट्यूटोरियल का इस्तेमाल कैसे किया जाएगा?

सिर्फ़ इसे पढ़ें इसे पढ़ें और कसरतों को पूरा करें

Python के साथ अपने अनुभव को आप कितनी रेटिंग देंगे?

शुरुआती इंटरमीडिएट कुशल

Google Cloud की सेवाएं इस्तेमाल करने का आपका अनुभव कैसा रहा?

शुरुआती इंटरमीडिएट कुशल

2. बैकग्राउंड

मॉड्यूल 7 से पता चलता है कि Python 2 फ़्लास्क App Engine ऐप्लिकेशन में, App Engine टास्क सूची के पुश टास्क इस्तेमाल करने का तरीका कैसे पता चलता है. मॉड्यूल 8 में, आप उस ऐप्लिकेशन को टास्क सूची से Cloud Tasks में माइग्रेट कर सकते हैं. मॉड्यूल 9 में आप इस सफ़र को जारी रखते हैं और उस ऐप्लिकेशन को Python 3 में पोर्ट करते हैं. साथ ही, आप Datastore के ऐक्सेस को Cloud NDB के बजाय, नेटिव Cloud Datastore क्लाइंट लाइब्रेरी पर स्विच करते हैं.

Cloud NDB, Python 2 और 3, दोनों के लिए काम करता है. इसलिए, यह App Engine के उन उपयोगकर्ताओं के लिए काफ़ी है जो अपने ऐप्लिकेशन को Python 2 से 3 पर पोर्ट करते हैं. क्लाइंट लाइब्रेरी का Cloud Datastore में एक और माइग्रेशन पूरी तरह से ज़रूरी नहीं है और इस पर विचार करने की सिर्फ़ एक वजह है: आपके पास ऐसे गैर-App Engine ऐप्लिकेशन (और/या Python 3 App Engine ऐप्लिकेशन) हैं जो पहले से Cloud Datastore क्लाइंट लाइब्रेरी का इस्तेमाल कर रहे हैं और आपको अपने कोडबेस को सिर्फ़ एक क्लाइंट लाइब्रेरी से Datastore ऐक्सेस करने के लिए इकट्ठा करना है. Cloud NDB को खास तौर पर, Python 2 App Engine डेवलपर के लिए, Python 3 माइग्रेशन टूल के तौर पर बनाया गया था. इसलिए, अगर आपके पास Cloud Datastore क्लाइंट लाइब्रेरी का इस्तेमाल करने वाला कोड नहीं है, तो आपको इस माइग्रेशन की ज़रूरत न पड़े.

आखिर में, Cloud Tasks क्लाइंट लाइब्रेरी का डेवलपमेंट सिर्फ़ Python 3 में जारी रहता है. इसलिए, हम "माइग्रेट" कर रहे हैं Python 2 के आखिरी वर्शन से लेकर उसके Python 3 के मौजूदा वर्शन तक. अच्छी बात यह है कि Python 2 में कोई नुकसान नहीं पहुंचा है. इसका मतलब है कि आपको कुछ और करने की ज़रूरत नहीं है.

इस ट्यूटोरियल में ये चरण बताए गए हैं:

  1. सेटअप/प्रीवर्क
  2. कॉन्फ़िगरेशन अपडेट करें
  3. ऐप्लिकेशन कोड बदलें

3. सेटअप/प्रीवर्क

इस सेक्शन में, इन कामों को करने का तरीका बताया गया है:

  1. अपना क्लाउड प्रोजेक्ट सेट अप करें
  2. बेसलाइन ऐप्लिकेशन का नमूना डाउनलोड करें
  3. (फिर से) बेसलाइन ऐप्लिकेशन डिप्लॉय करना और उसकी पुष्टि करना

इन चरणों से यह पक्का होता है कि कोड काम कर रहा है और यह Cloud की सेवाओं पर माइग्रेट होने के लिए तैयार है.

1. प्रोजेक्ट सेटअप करें

अगर आपने मॉड्यूल 8 कोडलैब पूरा कर लिया है, तो उसी प्रोजेक्ट (और कोड) का फिर से इस्तेमाल करें. इसके अलावा, नया प्रोजेक्ट बनाएं या किसी मौजूदा प्रोजेक्ट का फिर से इस्तेमाल करें. पक्का करें कि प्रोजेक्ट में एक चालू बिलिंग खाता और चालू App Engine ऐप्लिकेशन हो. अपना प्रोजेक्ट आईडी ढूंढें, क्योंकि कोडलैब (कोड बनाना सीखना) के दौरान आपको इसे अपने पास रखने की ज़रूरत है. इसका इस्तेमाल तब करें, जब आपको PROJECT_ID वैरिएबल मिले.

2. बेसलाइन ऐप्लिकेशन का नमूना डाउनलोड करें

इसकी ज़रूरी शर्तों में से एक है, Module 8 App Engine ऐप्लिकेशन: मॉड्यूल 8 कोडलैब (कोड बनाना सीखना) पूरा करें या रेपो से मॉड्यूल 8 ऐप्लिकेशन कॉपी करें. आप अपना या हमारा, मॉड्यूल 8 कोड इस्तेमाल करें, जहां से हम शुरुआत करेंगे ("START"). कोडलैब से आपको माइग्रेशन की प्रोसेस के बारे में जानकारी मिलती है. इससे यह पता चलता है कि कोड 9 रिपो फ़ोल्डर ("FINISH") में मौजूद कोड से मेल खाता है या नहीं.

आप चाहे जो भी मॉड्यूल 7 ऐप्लिकेशन इस्तेमाल करें, फ़ोल्डर यहां दिए गए फ़ोल्डर की तरह दिखना चाहिए. इसके अलावा, यह lib फ़ोल्डर के साथ भी दिख सकता है:

$ ls
README.md               appengine_config.py     requirements.txt
app.yaml                main.py                 templates

3. (फिर से) बेसलाइन ऐप्लिकेशन डिप्लॉय करना और उसकी पुष्टि करना

मॉड्यूल 8 ऐप्लिकेशन को डिप्लॉय करने के लिए, यह तरीका अपनाएं:

  1. अगर lib फ़ोल्डर मौजूद है, तो उसे मिटा दें और lib को फिर से भरने के लिए pip install -t lib -r requirements.txt चलाएं. अगर आपकी डेवलपमेंट मशीन पर Python 2 और 3, दोनों इंस्टॉल किए गए हैं, तो आपको इसके बजाय pip2 का इस्तेमाल करना पड़ सकता है.
  2. पक्का करें कि आपने gcloud कमांड-लाइन टूल इंस्टॉल किया हो और उसे शुरू किया हो. साथ ही, इसके इस्तेमाल की जानकारी की समीक्षा की हो.
  3. (ज़रूरी नहीं) अगर आपको हर gcloud निर्देश के साथ PROJECT_ID नहीं डालना है, तो अपने क्लाउड प्रोजेक्ट को gcloud config set project PROJECT_ID के साथ सेट करें.
  4. gcloud app deploy के साथ सैंपल ऐप्लिकेशन डिप्लॉय करें
  5. पक्का करें कि ऐप्लिकेशन बिना किसी समस्या के ठीक से काम कर रहा हो. अगर आपने मॉड्यूल 8 कोडलैब (कोड बनाना सीखना) पूरा कर लिया है, तो ऐप्लिकेशन सबसे हाल में वेबसाइट पर आने वालों की संख्या के साथ-साथ वेबसाइट पर आने वाले लोगों की संख्या भी दिखाता है. इसका उदाहरण नीचे दिया गया है. सबसे नीचे उन पुराने टास्क की जानकारी दी गई है जिन्हें मिटा दिया जाएगा.

4aa8a2cb5f527079.png

4. कॉन्फ़िगरेशन अपडेट करें

requirements.txt

नया requirements.txt करीब-करीब मॉड्यूल 8 वाले जैसा ही है. इसमें सिर्फ़ एक बड़ा बदलाव किया गया है: google-cloud-ndb को google-cloud-datastore से बदल दें. यह बदलाव करें, ताकि आपकी requirements.txt फ़ाइल कुछ ऐसी दिखे:

flask
google-cloud-datastore
google-cloud-tasks

इस requirements.txt फ़ाइल में कोई वर्शन नंबर मौजूद नहीं है. इसका मतलब है कि नए वर्शन चुने गए हैं. अगर कोई गड़बड़ी होती है, तो किसी ऐप्लिकेशन के काम करने वाले वर्शन लॉक-इन करने के लिए, वर्शन नंबरों का इस्तेमाल करना सामान्य तरीका माना जाता है.

app.yaml

दूसरी पीढ़ी का App Engine रनटाइम 2.x जैसी पहले से मौजूद तीसरे पक्ष की लाइब्रेरी के साथ काम नहीं करता और न ही पहले से मौजूद नहीं की लाइब्रेरी को कॉपी करने की सुविधा देता है. तीसरे पक्ष के पैकेज को सिर्फ़ requirements.txt में लिस्ट करना ज़रूरी है. इस वजह से, app.yaml का पूरा libraries सेक्शन मिटाया जा सकता है.

एक और अपडेट यह है कि Python 3 रनटाइम के लिए ऐसे वेब फ़्रेमवर्क का इस्तेमाल करना ज़रूरी है जो अपना खुद का रूटिंग करते हैं. इस वजह से, सभी स्क्रिप्ट हैंडलर को auto में बदलना ज़रूरी है. हालांकि, सभी रूट बदलकर auto होना ज़रूरी है और इस सैंपल ऐप्लिकेशन से कोई स्टैटिक फ़ाइल नहीं दिखाई जाती है, इसलिए कोई हैंडलर होना ज़रूरी नहीं है. इसलिए, पूरे handlers सेक्शन को भी हटा दें.

app.yaml में आपको बस रनटाइम को Python 3 के काम करने वाले वर्शन, जैसे कि 3.10 पर सेट करना होगा. यह बदलाव करें, ताकि नया और छोटा किया गया app.yaml सिर्फ़ यही एक लाइन हो:

runtime: python310

appengine_config.py और lib हटाएं

अगली-पीढ़ी की टेक्नोलॉजी के हिसाब से, App Engine के रनटाइम की मदद से तीसरे पक्ष के पैकेज के इस्तेमाल में बदलाव किया जाता है:

  • पहले से मौजूद लाइब्रेरी, ऐसी लाइब्रेरी होती हैं जिनकी जांच Google करता है और इन्हें App Engine के सर्वर पर उपलब्ध कराया जाता है. ऐसा इसलिए होता है, क्योंकि इनमें C/C++ कोड मौजूद होता है, जिसे डेवलपर क्लाउड पर डिप्लॉय नहीं कर सकते—ये अब दूसरी पीढ़ी के रनटाइम में उपलब्ध नहीं होते.
  • पहले से मौजूद लाइब्रेरी (कभी-कभी "वेंडिंग" या "सेल्फ़-बंडलिंग" भी कहा जाता है) को कॉपी करने की ज़रूरत अब दूसरी जनरेशन के रनटाइम में नहीं होगी. इसके बजाय, उन्हें requirements.txt में शामिल किया जाना चाहिए. यहां बिल्ड सिस्टम डिप्लॉय करते समय, आपकी ओर से इन्हें अपने-आप इंस्टॉल करता है.

तीसरे पक्ष के पैकेज मैनेजमेंट में किए गए बदलावों की वजह से, न तो appengine_config.py फ़ाइल और न ही lib फ़ोल्डर की ज़रूरत है. इसलिए, इन्हें मिटा दें. दूसरी जनरेशन के रनटाइम में, App Engine की मदद से requirements.txt में दिए गए तीसरे पक्ष के पैकेज अपने-आप इंस्टॉल हो जाते हैं. खास जानकारी:

  1. किसी तीसरे पक्ष की लाइब्रेरी को खुद से बंडल या कॉपी नहीं किया जाना चाहिए; उन्हें requirements.txt में दिखाओ
  2. lib फ़ोल्डर में कोई pip install नहीं है. इसका मतलब है कि lib फ़ोल्डर में कोई पीरियड नहीं है
  3. app.yaml में पहले से मौजूद तीसरे पक्ष की लाइब्रेरी की कोई सूची नहीं है (इसलिए, libraries सेक्शन नहीं है); उन्हें requirements.txt में लिस्ट करो
  4. आपके ऐप्लिकेशन से रेफ़रंस के लिए तीसरे पक्ष की कोई भी लाइब्रेरी नहीं होने का मतलब है कि कोई appengine_config.py फ़ाइल नहीं है

सिर्फ़ requirements.txt में तीसरे पक्ष की सभी लाइब्रेरी की जानकारी देना, डेवलपर के लिए ज़रूरी है.

5. ऐप्लिकेशन फ़ाइलें अपडेट करें

यहां सिर्फ़ एक ऐप्लिकेशन फ़ाइल है, main.py, इसलिए इस सेक्शन में किए गए सभी बदलाव सिर्फ़ उस फ़ाइल पर असर डालते हैं. नीचे "अंतर" दिया गया है मौजूदा कोड को नए ऐप्लिकेशन में रीफ़ैक्टर करने के लिए, किए जाने वाले सभी बदलावों की जानकारी दी गई है. पाठकों को कोड लाइन-दर-लाइन पढ़ने की उम्मीद नहीं होती है, क्योंकि इसका मकसद यह दिखाना है कि इस रीफ़ैक्टर में क्या ज़रूरी है. हालांकि, बेझिझक नए टैब में खोलें या ज़रूरत के हिसाब से कोड को डाउनलोड और ज़ूम इन करें.

5d043768ba7be742.png

इंपोर्ट और शुरू करने की प्रोसेस अपडेट करें

मॉड्यूल 8 के लिए, main.py में मौजूद इंपोर्ट सेक्शन में, Cloud NDB और Cloud Tasks का इस्तेमाल किया जाता है; तो वह इस तरह दिखना चाहिए:

पहले:

from datetime import datetime
import json
import logging
import time
from flask import Flask, render_template, request
import google.auth
from google.cloud import ndb, tasks

app = Flask(__name__)
ds_client = ndb.Client()
ts_client = tasks.CloudTasksClient()

Python 3 जैसे दूसरी जनरेशन के रनटाइम में लॉग इन करना आसान और बेहतर हो जाता है:

  • बेहतर तरीके से डेटा इकट्ठा करने के लिए, Cloud Logging का इस्तेमाल करें
  • आसानी से लॉगिंग के लिए, बस print() के ज़रिए stdout (या stderr) पर भेजें
  • Python logging मॉड्यूल का इस्तेमाल करने की कोई ज़रूरत नहीं है. इसलिए, इसे हटा दें

इसलिए, logging को इंपोर्ट करें और google.cloud.ndb को google.cloud.datastore से स्वैप करें. इसी तरह, ds_client को बदलकर, NDB क्लाइंट के बजाय Datastore क्लाइंट पर ले जाएं. इन बदलावों के साथ, आपके नए ऐप्लिकेशन का ऊपरी हिस्सा अब कुछ ऐसा दिखेगा:

बाद में:

from datetime import datetime
import json
import time
from flask import Flask, render_template, request
import google.auth
from google.cloud import datastore, tasks

app = Flask(__name__)
ds_client = datastore.Client()
ts_client = tasks.CloudTasksClient()

Cloud Datastore पर माइग्रेट करें

अब समय आ गया है कि NDB क्लाइंट लाइब्रेरी के इस्तेमाल को Datastore से बदला जाए. App Engine NDB और Cloud NDB, दोनों के लिए डेटा मॉडल (क्लास) की ज़रूरत होती है; इस ऐप्लिकेशन के लिए, यह Visit है. store_visit() फ़ंक्शन, दूसरे सभी माइग्रेशन मॉड्यूल में एक ही तरह से काम करता है: यह विज़िट को रजिस्टर करने के लिए, नया Visit रिकॉर्ड बनाता है. साथ ही, विज़िट करने वाले क्लाइंट का आईपी पता और उपयोगकर्ता एजेंट (ब्राउज़र टाइप) को सेव करता है.

पहले:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

हालांकि, Cloud Datastore डेटा मॉडल की क्लास का इस्तेमाल नहीं करता. इसलिए, इस क्लास को मिटा दें. इसके अलावा, रिकॉर्ड बनाए जाने पर Cloud Datastore अपने-आप टाइमस्टैंप नहीं बनाता है. ऐसे में, आपको मैन्युअल तरीके से टाइमस्टैंप बनाना पड़ता है. datetime.now() कॉल की मदद से ऐसा किया जाता है.

डेटा क्लास के बिना, आपका बदला गया store_visit() ऐसा दिखना चाहिए:

बाद में:

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    entity = datastore.Entity(key=ds_client.key('Visit'))
    entity.update({
        'timestamp': datetime.now(),
        'visitor': '{}: {}'.format(remote_addr, user_agent),
    })
    ds_client.put(entity)

इसका मुख्य फ़ंक्शन fetch_visits() है. यह न सिर्फ़ हाल के Visit के लिए मूल क्वेरी करता है, बल्कि यह आखिरी Visit के टाइमस्टैंप का भी इस्तेमाल करता है. साथ ही, एक पुश टास्क बनाता है जो /trim (इस तरह trim()) को पुराने Visit के सभी हिस्सों को एक साथ मिटाने के लिए कॉल करता है. यहां Cloud NDB का इस्तेमाल किया जा रहा है:

पहले:

def fetch_visits(limit):
    'get most recent visits & add task to delete older visits'
    with ds_client.context():
        data = Visit.query().order(-Visit.timestamp).fetch(limit)
    oldest = time.mktime(data[-1].timestamp.timetuple())
    oldest_str = time.ctime(oldest)
    logging.info('Delete entities older than %s' % oldest_str)
    task = {
        'app_engine_http_request': {
            'relative_uri': '/trim',
            'body': json.dumps({'oldest': oldest}).encode(),
            'headers': {
                'Content-Type': 'application/json',
            },
        }
    }
    ts_client.create_task(parent=QUEUE_PATH, task=task)
    return (v.to_dict() for v in data), oldest_str

इनमें हुए मुख्य बदलाव:

  1. Cloud Datastore के मिलते-जुलते वर्शन के लिए, Cloud NDB क्वेरी को स्वैप करें; क्वेरी स्टाइल थोड़ा अलग हैं.
  2. Datastore के लिए न ही कॉन्टेक्स्ट मैनेजर की ज़रूरत होती है और न ही यह आपको उसका डेटा (to_dict() के साथ) एक्सट्रैक्ट करता है, जैसे Cloud NDB करता है.
  3. कॉल लॉग करने की सेटिंग को print() से बदलें

इन बदलावों के बाद, fetch_visits() ऐसा दिखेगा:

बाद में:

def fetch_visits(limit):
    'get most recent visits & add task to delete older visits'
    query = ds_client.query(kind='Visit')
    query.order = ['-timestamp']
    visits = list(query.fetch(limit=limit))
    oldest = time.mktime(visits[-1]['timestamp'].timetuple())
    oldest_str = time.ctime(oldest)
    print('Delete entities older than %s' % oldest_str)
    task = {
        'app_engine_http_request': {
            'relative_uri': '/trim',
            'body': json.dumps({'oldest': oldest}).encode(),
            'headers': {
                'Content-Type': 'application/json',
            },
        }
    }
    ts_client.create_task(parent=QUEUE_PATH, task=task)
    return visits, oldest_str

आम तौर पर, इसकी ज़रूरत होती है. माफ़ करें, एक बड़ी समस्या है.

(शायद) एक नई (पुश) सूची बनाएं

मॉड्यूल 7 में, हमने मौजूदा मॉड्यूल 1 ऐप्लिकेशन में App Engine taskqueue के इस्तेमाल को जोड़ा है. लेगसी App Engine सुविधा के तौर पर पुश टास्क करने का एक मुख्य फ़ायदा यह है कि "डिफ़ॉल्ट" सूची अपने-आप बन जाती है. जब इस ऐप्लिकेशन को मॉड्यूल 8 में Cloud Tasks पर माइग्रेट किया गया था, तब डिफ़ॉल्ट सूची पहले से मौजूद थी. इसलिए, अब भी हमें इस बारे में परेशान होने की ज़रूरत नहीं थी. जो कि मॉड्यूल 9 में बदल जाएगा.

एक महत्वपूर्ण पहलू यह है कि नया App Engine ऐप्लिकेशन अब App Engine सेवाओं का उपयोग नहीं करता है और इसलिए, अब आप यह नहीं मान सकते कि App Engine किसी अन्य उत्पाद (क्लाउड कार्य) में अपने आप ही कार्य सूची बना देता है. जैसा कि लिखा गया है, fetch_visits() (जो सूची पहले से मौजूद नहीं है) में टास्क नहीं बनाया जा सकेगा. यह जांचने के लिए एक नए फ़ंक्शन की ज़रूरत है कि क्या ("डिफ़ॉल्ट") सूची मौजूद है और अगर नहीं है, तो एक सूची बनाएं.

इस फ़ंक्शन को _create_queue_if() कॉल करें और इसे fetch_visits() के ठीक ऊपर अपने ऐप्लिकेशन में जोड़ें क्योंकि यहीं पर इसे कॉल किया जाता है. फ़ंक्शन का मुख्य हिस्सा, जिसे जोड़ना है:

def _create_queue_if():
    'app-internal function creating default queue if it does not exist'
    try:
        ts_client.get_queue(name=QUEUE_PATH)
    except Exception as e:
        if 'does not exist' in str(e):
            ts_client.create_queue(parent=PATH_PREFIX,
                    queue={'name': QUEUE_PATH})
    return True

Cloud Tasks create_queue() फ़ंक्शन के लिए, सूची का पूरा पाथ नेम डालना ज़रूरी है. इसमें सूची का नाम शामिल नहीं है. आसानी के लिए, QUEUE_PATH की सूची का नाम (QUEUE_PATH.rsplit('/', 2)[0]) घटाने पर, एक और वैरिएबल PATH_PREFIX बनाएं. इसकी परिभाषा सबसे ऊपर जोड़ें, ताकि सभी कॉन्सटैंट असाइनमेंट वाले कोड ब्लॉक इस तरह दिखें:

_, PROJECT_ID = google.auth.default()
REGION_ID = 'REGION_ID'    # replace w/your own
QUEUE_NAME = 'default'     # replace w/your own
QUEUE_PATH = ts_client.queue_path(PROJECT_ID, REGION_ID, QUEUE_NAME)
PATH_PREFIX = QUEUE_PATH.rsplit('/', 2)[0]

अब _create_queue_if() का इस्तेमाल करने के लिए, fetch_visits() की आखिरी लाइन में बदलाव करें. अगर ज़रूरी हो, तो पहले लाइन बनाएं. इसके बाद टास्क बनाएं:

    if _create_queue_if():
        ts_client.create_task(parent=QUEUE_PATH, task=task)
    return visits, oldest_str

_create_queue_if() और fetch_visits(), दोनों को अब एग्रीगेट तौर पर ऐसा दिखना चाहिए:

def _create_queue_if():
    'app-internal function creating default queue if it does not exist'
    try:
        ts_client.get_queue(name=QUEUE_PATH)
    except Exception as e:
        if 'does not exist' in str(e):
            ts_client.create_queue(parent=PATH_PREFIX,
                    queue={'name': QUEUE_PATH})
    return True

def fetch_visits(limit):
    'get most recent visits & add task to delete older visits'
    query = ds_client.query(kind='Visit')
    query.order = ['-timestamp']
    visits = list(query.fetch(limit=limit))
    oldest = time.mktime(visits[-1]['timestamp'].timetuple())
    oldest_str = time.ctime(oldest)
    print('Delete entities older than %s' % oldest_str)
    task = {
        'app_engine_http_request': {
            'relative_uri': '/trim',
            'body': json.dumps({'oldest': oldest}).encode(),
            'headers': {
                'Content-Type': 'application/json',
            },
        }
    }
    if _create_queue_if():
        ts_client.create_task(parent=QUEUE_PATH, task=task)
    return visits, oldest_str

इस अतिरिक्त कोड को जोड़ने के अलावा, बाकी क्लाउड टास्क कोड, मॉड्यूल 8 में मौजूद नहीं हैं. कोड का आखिरी हिस्सा टास्क हैंडलर है.

अपडेट (पुश) टास्क हैंडलर

टास्क हैंडलर trim() में, सबसे पुरानी विज़िट से पहले की विज़िट के लिए Cloud NDB कोड क्वेरी करता है. यह तेज़ी से काम करने के लिए सिर्फ़ पासकोड वाली क्वेरी का इस्तेमाल करता है—अगर आपको सिर्फ़ विज़िट आईडी की ज़रूरत है, तो सारा डेटा क्यों फ़ेच किया जाएगा? सभी विज़िट आईडी हासिल करने के बाद, उन सभी को Cloud NDB के delete_multi() फ़ंक्शन की मदद से बैच में मिटाएं.

पहले:

@app.route('/trim', methods=['POST'])
def trim():
    '(push) task queue handler to delete oldest visits'
    oldest = float(request.get_json().get('oldest'))
    with ds_client.context():
        keys = Visit.query(
                Visit.timestamp < datetime.fromtimestamp(oldest)
        ).fetch(keys_only=True)
        nkeys = len(keys)
        if nkeys:
            logging.info('Deleting %d entities: %s' % (
                    nkeys, ', '.join(str(k.id()) for k in keys)))
            ndb.delete_multi(keys)
        else:
            logging.info(
                    'No entities older than: %s' % time.ctime(oldest))
    return ''   # need to return SOME string w/200

fetch_visits() की तरह ही, ज़्यादातर बदलावों में Cloud Datastore के लिए Cloud NDB कोड को बदलना, क्वेरी की स्टाइल बदलना, उसके कॉन्टेक्स्ट मैनेजर का इस्तेमाल हटाना, और लॉगिंग कॉल को print() में बदलना शामिल है.

बाद में:

@app.route('/trim', methods=['POST'])
def trim():
    '(push) task queue handler to delete oldest visits'
    oldest = float(request.get_json().get('oldest'))
    query = ds_client.query(kind='Visit')
    query.add_filter('timestamp', '<', datetime.fromtimestamp(oldest))
    query.keys_only()
    keys = list(visit.key for visit in query.fetch())
    nkeys = len(keys)
    if nkeys:
        print('Deleting %d entities: %s' % (
                nkeys, ', '.join(str(k.id) for k in keys)))
        ds_client.delete_multi(keys)
    else:
        print('No entities older than: %s' % time.ctime(oldest))
    return ''   # need to return SOME string w/200

मुख्य ऐप्लिकेशन हैंडलर root() में कोई बदलाव नहीं हुआ है.

Python 3 पर पोर्ट करना

इस ऐप्लिकेशन का नमूना, Python 2 और 3, दोनों पर चलने के लिए डिज़ाइन किया गया था. Python 3 से जुड़े बदलावों के बारे में पहले इस ट्यूटोरियल के काम के सेक्शन में बताया गया था. इसके लिए, आपको अलग से कोई चरण नहीं करना होगा और न ही कंपैटबिलिटी लाइब्रेरी की ज़रूरत होगी.

Cloud Tasks अपडेट

Python 2 के साथ काम करने वाले Cloud Tasks क्लाइंट लाइब्रेरी का आखिरी वर्शन 1.5.0 है. जवाब लिखते समय, Python 3 के लिए क्लाइंट लाइब्रेरी का नया वर्शन, उस वर्शन पर पूरी तरह से काम करता है. इसलिए, किसी और अपडेट की ज़रूरत नहीं है.

एचटीएमएल टेंप्लेट का अपडेट

एचटीएमएल टेंप्लेट फ़ाइल, templates/index.html में भी किसी बदलाव की ज़रूरत नहीं है. इसलिए, मॉड्यूल 9 ऐप्लिकेशन में आने वाले सभी ज़रूरी बदलावों को इसमें शामिल कर लिया गया है.

6. खास जानकारी/क्लीनअप

ऐप्लिकेशन डिप्लॉय करें और उसकी पुष्टि करें

कोड के अपडेट पूरे करने के बाद, अपने ऐप्लिकेशन को gcloud app deploy के साथ डिप्लॉय करें. ऐसा मुख्य रूप से Python 3 के पोर्ट में किया जाता है. आउटपुट, मॉड्यूल 7 और 8 ऐप्लिकेशन के ऐप्लिकेशन के जैसा होना चाहिए. हालांकि, अगर आपने डेटाबेस के ऐक्सेस को Cloud Datastore क्लाइंट लाइब्रेरी में भेज दिया है और Python 3 में अपग्रेड कर लिया है:

मॉड्यूल 7 visitme ऐप्लिकेशन

यह चरण कोडलैब को पूरा करता है. हम चाहते हैं कि आप अपने कोड की तुलना, मॉड्यूल 9 फ़ोल्डर में मौजूद कोड से करें. बधाई हो!

व्यवस्थित करें

सामान्य

अगर आपका काम अभी हो गया है, तो हमारा सुझाव है कि आप बिलिंग से बचने के लिए अपना App Engine ऐप्लिकेशन बंद कर दें. हालांकि, अगर आपको कुछ और टेस्ट या एक्सपेरिमेंट करना है, तो App Engine प्लैटफ़ॉर्म का एक मुफ़्त कोटा है. अगर इस्तेमाल के टीयर को पार नहीं किया जा रहा है, तो आपसे शुल्क नहीं लिया जाएगा. यह कंप्यूट के लिए है. हालांकि, काम के App Engine की सेवाओं के लिए भी शुल्क लिया जा सकता है. इसलिए, ज़्यादा जानकारी के लिए इसका कीमत पेज देखें. अगर इस माइग्रेशन में क्लाउड की अन्य सेवाएं शामिल हैं, तो उनका बिल अलग से भेजा जाता है. दोनों ही मामलों में, अगर लागू हो, तो "इस कोडलैब के लिए खास" सेक्शन देखें सेक्शन देखें.

अगर आपको पूरी जानकारी देनी है, तो App Engine जैसे Google Cloud के बिना सर्वर वाले कंप्यूट प्लैटफ़ॉर्म पर डिप्लॉय करने पर, मामूली बनाने और स्टोरेज का खर्च उठाना पड़ता है. Cloud Storage की तरह Cloud Build का अपना अलग कोटा होता है. उस इमेज का स्टोरेज, उसके कुछ हिस्से का इस्तेमाल करता है. हालांकि, हो सकता है कि आप किसी ऐसे क्षेत्र में हों जहां ऐसा कोई फ़्री टीयर उपलब्ध न हो. इसलिए, संभावित लागत को कम करने के लिए, अपने स्टोरेज के इस्तेमाल को ध्यान में रखें. Cloud Storage के लिए तय किए गए "फ़ोल्डर" तो आपको इन चीज़ों की समीक्षा करनी चाहिए:

  • console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/images
  • console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
  • ऊपर दिए गए स्टोरेज लिंक, आपके PROJECT_ID और *LOC*ेशन के हिसाब से होते हैं. जैसे, "us" अगर आपका ऐप्लिकेशन अमेरिका में होस्ट किया जाता है.

दूसरी ओर, अगर आपको इस ऐप्लिकेशन या इससे जुड़े दूसरे माइग्रेशन कोडलैब का इस्तेमाल नहीं करना है और सब कुछ पूरी तरह से मिटाना है, तो अपना प्रोजेक्ट बंद कर दें.

इस कोडलैब के लिए खास

नीचे दी गई सेवाएं, इस कोडलैब के लिए यूनीक हैं. ज़्यादा जानकारी के लिए हर प्रॉडक्ट के दस्तावेज़ देखें:

अगले चरण

इसके बाद, ऐप्लिकेशन इंजन टास्क की सूची के पुश टास्क से क्लाउड टास्क में माइग्रेट हो जाता है. मॉड्यूल 3 में Cloud NDB से Cloud Datastore में वैकल्पिक माइग्रेशन भी अपने-आप (टास्क सूची या क्लाउड टास्क के बिना) शामिल है. मॉड्यूल 3 के अलावा, कुछ ऐसे माइग्रेशन मॉड्यूल हैं जो App Engine की लेगसी बंडल सेवाओं का इस्तेमाल बंद करने पर फ़ोकस करते हैं. इन मॉड्यूल में ये शामिल हैं:

Google Cloud में, अब सिर्फ़ बिना सर्वर वाला प्लैटफ़ॉर्म App Engine है. अगर आपके पास कोई छोटा App Engine ऐप्लिकेशन है या कोई ऐसा ऐप्लिकेशन है जिसमें सीमित सुविधाएं हैं और आपको उसे स्टैंडअलोन माइक्रोसर्विस में बदलना है या किसी मोनोलिथिक ऐप्लिकेशन को फिर से इस्तेमाल किए जा सकने वाले कई कॉम्पोनेंट में बांटना है, तो Cloud Functions का इस्तेमाल करने के बारे में सोचें. अगर कंटेनराइज़ेशन आपके ऐप्लिकेशन डेवलपमेंट वर्कफ़्लो का हिस्सा बन गया है, तो खास तौर पर अगर उसमें CI/CD (लगातार इंटिग्रेशन/लगातार डिलीवरी या डिप्लॉयमेंट) पाइपलाइन शामिल है, तो Cloud Run पर माइग्रेट करें. इन स्थितियों की जानकारी यहां दिए गए मॉड्यूल में दी गई है:

  • App Engine से Cloud Functions पर माइग्रेट करना: मॉड्यूल 11 देखें
  • App Engine से Cloud Run पर माइग्रेट करना: अपने ऐप्लिकेशन को Docker के साथ कंटेनर बनाने के लिए, मॉड्यूल 4 देखें. इसके अलावा, कंटेनर, Docker नॉलेज या Dockerfiles के बिना ऐसा करने के लिए मॉड्यूल 5 पर जाएं

बिना सर्वर वाले किसी दूसरे प्लैटफ़ॉर्म पर स्विच करना ज़रूरी नहीं है. हमारा सुझाव है कि कोई भी बदलाव करने से पहले, अपने ऐप्लिकेशन और इस्तेमाल के उदाहरण देखने के लिए सबसे सही विकल्प चुनें.

आप आगे चाहे किसी माइग्रेशन मॉड्यूल पर जाएं, सर्वरलेस माइग्रेशन स्टेशन का पूरा कॉन्टेंट (कोडलैब, वीडियो, सोर्स कोड [जब उपलब्ध हो]) उसके ओपन सोर्स रेपो से ऐक्सेस किया जा सकता है. डेटा स्टोर करने की जगह के README में, यह भी बताया गया है कि किस माइग्रेशन पर विचार करना चाहिए. साथ ही, इसमें किसी "ऑर्डर" के बारे में भी बताया गया है. में तय किया गया है.

7. अन्य संसाधन

कोड लैब से जुड़ी समस्याएं/सुझाव

अगर आपको इस कोडलैब के साथ कोई समस्या मिलती है, तो कृपया आवेदन करने से पहले अपनी समस्या का पता लगाएं. खोजने और नई समस्याएं बनाने के लिए लिंक:

माइग्रेशन के लिए संसाधन

यहां दी गई टेबल में, मॉड्यूल 8 (START) और मॉड्यूल 9 (FINISH) के रेपो फ़ोल्डर के लिंक दिए गए हैं. उन्हें सभी App Engine कोडलैब माइग्रेशन के लिए रेपो से भी ऐक्सेस किया जा सकता है, जिसका क्लोन बनाया जा सकता है या किसी ZIP फ़ाइल को डाउनलोड किया जा सकता है.

Codelab

Python 2

Python 3

मॉड्यूल 8

कोड

(लागू नहीं)

मॉड्यूल 9

(लागू नहीं)

कोड

ऑनलाइन संसाधन

नीचे कुछ ऑनलाइन संसाधन दिए गए हैं, जो इस ट्यूटोरियल के लिए काम के हो सकते हैं:

App Engine

क्लाउड एनडीबी

Cloud Datastore

Cloud Tasks

क्लाउड से जुड़ी अन्य जानकारी

लाइसेंस

इस काम को क्रिएटिव कॉमंस एट्रिब्यूशन 2.0 जेनरिक लाइसेंस के तहत लाइसेंस मिला है.