مهاجرت یک موتور برنامه پایتون 2 Cloud NDB & برنامه Cloud Tasks به Python 3 و Cloud Datastore (ماژول 9)

۱. مرور کلی

مجموعه آزمایشگاه‌های کد Serverless Migration Station (آموزش‌های عملی و خودآموز) و ویدیوهای مرتبط با آن ، با هدف کمک به توسعه‌دهندگان Google Cloud serverless برای مدرن‌سازی برنامه‌هایشان، با راهنمایی آنها در طول یک یا چند مهاجرت، و در درجه اول دور شدن از سرویس‌های قدیمی، ارائه می‌شوند. انجام این کار، برنامه‌های شما را قابل حمل‌تر می‌کند و گزینه‌ها و انعطاف‌پذیری بیشتری به شما می‌دهد و شما را قادر می‌سازد تا با طیف وسیع‌تری از محصولات Cloud ادغام شده و به آنها دسترسی داشته باشید و به راحتی به نسخه‌های جدیدتر زبان ارتقا دهید. در حالی که در ابتدا بر روی اولین کاربران Cloud، در درجه اول توسعه‌دهندگان App Engine (محیط استاندارد)، تمرکز دارد، این مجموعه به اندازه کافی گسترده است که شامل سایر پلتفرم‌های serverless مانند Cloud Functions و Cloud Run یا در صورت لزوم، هر جای دیگری نیز می‌شود.

هدف از این آزمایشگاه کد، انتقال برنامه نمونه ماژول ۸ به پایتون ۳ و همچنین تغییر دسترسی Datastore (Cloud Firestore در حالت Datastore) از استفاده از Cloud NDB به کتابخانه کلاینت Cloud Datastore بومی و ارتقاء به آخرین نسخه کتابخانه کلاینت Cloud Tasks است.

ما استفاده از صف وظایف (Task Queue) را برای وظایف push در ماژول ۷ اضافه کردیم، سپس این کاربرد را در ماژول ۸ به Cloud Tasks منتقل کردیم. در ماژول ۹، به پایتون ۳ و Cloud Datastore ادامه می‌دهیم. کسانی که از صف‌های وظایف (Task Queues) برای وظایف pull استفاده می‌کنند، به Cloud Pub/Sub مهاجرت می‌کنند و باید به ماژول‌های ۱۸-۱۹ مراجعه کنند.

یاد خواهید گرفت که چگونه

  • انتقال برنامه نمونه ماژول ۸ به پایتون ۳
  • دسترسی به Datastore را از Cloud NDB به کتابخانه‌های کلاینت Cloud Datastore تغییر دهید
  • به آخرین نسخه کتابخانه کلاینت Cloud Tasks ارتقا دهید

آنچه نیاز دارید

نظرسنجی

چگونه از این آموزش استفاده خواهید کرد؟

فقط آن را بخوانید آن را بخوانید و تمرین‌ها را انجام دهید

تجربه خود را با پایتون چگونه ارزیابی می‌کنید؟

تازه کار متوسط ماهر

تجربه خود را در استفاده از خدمات ابری گوگل چگونه ارزیابی می‌کنید؟

تازه کار متوسط ماهر

۲. پیشینه

ماژول 7 نحوه استفاده از App Engine Task Queue push tasks را در برنامه‌های Python 2 Flask App Engine نشان می‌دهد. در ماژول 8 ، آن برنامه را از Task Queue به Cloud Tasks منتقل می‌کنید. در اینجا در ماژول 9 ، این سفر را ادامه می‌دهید و آن برنامه را به Python 3 منتقل می‌کنید و همچنین دسترسی Datastore را از استفاده از Cloud NDB به کتابخانه کلاینت Cloud Datastore بومی تغییر می‌دهید.

از آنجایی که Cloud NDB هم برای پایتون ۲ و هم برای پایتون ۳ کار می‌کند، برای کاربران App Engine که برنامه‌های خود را از پایتون ۲ به ۳ منتقل می‌کنند، کافی است. انتقال اضافی کتابخانه‌های کلاینت به Cloud Datastore کاملاً اختیاری است و تنها یک دلیل برای در نظر گرفتن آن وجود دارد: شما برنامه‌هایی غیر از App Engine (و/یا برنامه‌های Python 3 App Engine) دارید که از قبل از کتابخانه کلاینت Cloud Datastore استفاده می‌کنند و می‌خواهید پایگاه کد خود را برای دسترسی به Datastore تنها با یک کتابخانه کلاینت تجمیع کنید. Cloud NDB به طور خاص برای توسعه‌دهندگان Python 2 App Engine به عنوان ابزاری برای انتقال به پایتون ۳ ایجاد شده است، بنابراین اگر از قبل کدی با استفاده از کتابخانه کلاینت Cloud Datastore ندارید، نیازی به در نظر گرفتن این انتقال ندارید.

در نهایت، توسعه کتابخانه کلاینت Cloud Tasks فقط در پایتون ۳ ادامه دارد، بنابراین ما در حال "مهاجرت" از یکی از نسخه‌های نهایی پایتون ۲ به پایتون ۳ هم‌عصر آن هستیم. خوشبختانه، هیچ تغییر اساسی نسبت به پایتون ۲ وجود ندارد، به این معنی که در اینجا نیازی به انجام کار دیگری ندارید.

این آموزش شامل مراحل زیر است:

  1. راه‌اندازی/پیش‌پردازش
  2. پیکربندی را به‌روزرسانی کنید
  3. اصلاح کد برنامه

۳. تنظیمات/پیش‌پردازش

این بخش توضیح می‌دهد که چگونه:

  1. پروژه ابری خود را راه‌اندازی کنید
  2. دریافت برنامه نمونه پایه
  3. (دوباره)استقرار و اعتبارسنجی برنامه پایه

این مراحل تضمین می‌کنند که شما با کدی کار می‌کنید که به درستی کار می‌کند و برای انتقال به سرویس‌های ابری آماده است.

۱. پروژه راه‌اندازی

اگر آزمایشگاه کد ماژول ۸ را تکمیل کرده‌اید، از همان پروژه (و کد) دوباره استفاده کنید. روش دیگر، ایجاد یک پروژه کاملاً جدید یا استفاده مجدد از یک پروژه موجود دیگر است. مطمئن شوید که پروژه دارای یک حساب صورتحساب فعال و یک برنامه App Engine فعال است. شناسه پروژه خود را پیدا کنید زیرا در طول این آزمایشگاه کد به آن نیاز دارید و هر زمان که با متغیر PROJECT_ID مواجه شدید، از آن استفاده کنید.

۲. نمونه برنامه پایه را دریافت کنید

یکی از پیش‌نیازها، یک برنامه‌ی ماژول ۸ App Engine است که کار کند: کدلب ماژول ۸ (توصیه می‌شود) را تکمیل کنید یا برنامه‌ی ماژول ۸ را از مخزن کپی کنید. چه از کد خودتان استفاده کنید و چه از کد ما، کد ماژول ۸ جایی است که ما شروع می‌کنیم ("شروع"). این کدلب شما را در طول مهاجرت راهنمایی می‌کند و با کدی که شبیه کد موجود در پوشه‌ی مخزن ماژول ۹ است ("پایان")، به پایان می‌رسد.

صرف نظر از اینکه از کدام برنامه ماژول ۷ استفاده می‌کنید، پوشه باید مانند زیر باشد، احتمالاً شامل یک پوشه lib نیز خواهد بود:

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

۳. (دوباره) استقرار و اعتبارسنجی برنامه پایه

برای نصب برنامه ماژول ۸ مراحل زیر را انجام دهید:

  1. اگر پوشه lib وجود دارد، آن را حذف کنید و pip install -t lib -r requirements.txt را برای پر کردن مجدد lib اجرا کنید. اگر پایتون ۲ و ۳ را روی دستگاه توسعه خود نصب دارید، ممکن است لازم باشد از pip2 استفاده کنید.
  2. مطمئن شوید که ابزار خط فرمان gcloud را نصب و راه‌اندازی اولیه کرده‌اید و نحوه‌ی استفاده از آن را بررسی کرده‌اید.
  3. (اختیاری) اگر نمی‌خواهید PROJECT_ID با هر دستور gcloud وارد کنید، پروژه Cloud خود را با gcloud config set project PROJECT_ID تنظیم کنید.
  4. برنامه نمونه را با gcloud app deploy مستقر کنید
  5. تأیید کنید که برنامه طبق انتظار و بدون مشکل اجرا می‌شود. اگر ماژول ۸ codelab را تکمیل کرده باشید، برنامه بازدیدکنندگان برتر را به همراه جدیدترین بازدیدها (در زیر نشان داده شده است) نمایش می‌دهد. در پایین، نشانه‌ای از وظایف قدیمی‌تر که حذف خواهند شد، وجود دارد.

4aa8a2cb5f527079.png

۴. به‌روزرسانی پیکربندی

الزامات.txt

فایل requirements.txt جدید تقریباً مشابه فایل ماژول ۸ است، تنها با یک تغییر بزرگ: google-cloud-ndb را با google-cloud-datastore جایگزین کنید. این تغییر را ایجاد کنید تا فایل requirements.txt شما به این شکل باشد:

flask
google-cloud-datastore
google-cloud-tasks

این فایل requirements.txt هیچ شماره نسخه‌ای ندارد، به این معنی که آخرین نسخه‌ها انتخاب شده‌اند. در صورت بروز هرگونه ناسازگاری، استفاده از شماره نسخه‌ها برای قفل کردن نسخه‌های کاری برای یک برنامه، یک روش استاندارد است.

برنامه.yaml

نسل دوم App Engine runtime از کتابخانه‌های داخلی شخص ثالث مانند 2.x پشتیبانی نمی‌کند و همچنین از کپی کردن کتابخانه‌های غیر داخلی نیز پشتیبانی نمی‌کند. تنها الزام برای بسته‌های شخص ثالث، فهرست کردن آنها در requirements.txt است. در نتیجه، کل بخش libraries از app.yaml قابل حذف است.

به‌روزرسانی دیگر این است که زمان اجرای پایتون ۳ نیاز به استفاده از چارچوب‌های وب دارد که مسیریابی خود را انجام می‌دهند. در نتیجه، همه کنترل‌کننده‌های اسکریپت باید به auto تغییر داده شوند. با این حال، از آنجایی که همه مسیرها باید به auto تغییر داده شوند و هیچ فایل استاتیکی از این برنامه نمونه ارائه نمی‌شود، داشتن هیچ کنترل‌کننده‌ای بی‌ربط است، بنابراین کل بخش handlers را نیز حذف کنید.

تنها چیزی که در app.yaml لازم است، تنظیم زمان اجرا روی یک نسخه پشتیبانی شده از پایتون ۳، مثلاً ۳.۱۰، است. این تغییر را ایجاد کنید تا app.yaml جدید و مختصر شده فقط همین یک خط باشد:

runtime: python310

appengine_config.py و lib را حذف کنید

نسل بعدی زمان‌های اجرای App Engine، استفاده از بسته‌های شخص ثالث را اصلاح می‌کند:

  • کتابخانه‌های داخلی، کتابخانه‌هایی هستند که توسط گوگل بررسی و در سرورهای App Engine در دسترس قرار گرفته‌اند، احتمالاً به این دلیل که حاوی کد C/C++ هستند که توسعه‌دهندگان اجازه ندارند آن را در فضای ابری مستقر کنند - این کتابخانه‌ها دیگر در زمان‌های اجرای نسل دوم در دسترس نیستند.
  • کپی کردن کتابخانه‌های غیر داخلی (که گاهی اوقات "فروشی" یا "خود-بسته‌بندی" نامیده می‌شوند) دیگر در زمان‌های اجرای نسل دوم مورد نیاز نیست. در عوض، آنها باید در requirements.txt فهرست شوند، جایی که سیستم ساخت به طور خودکار آنها را از طرف شما در زمان استقرار نصب می‌کند.

در نتیجه‌ی این تغییرات در مدیریت بسته‌های شخص ثالث، نه فایل appengine_config.py و نه پوشه‌ی lib مورد نیاز نیستند، بنابراین آن‌ها را حذف کنید. در زمان‌های اجرای نسل دوم، App Engine به طور خودکار بسته‌های شخص ثالث ذکر شده در requirements.txt را نصب می‌کند. خلاصه:

  1. کتابخانه‌های خود-بسته‌بندی‌شده یا کپی‌شده از طرف شخص ثالث ممنوع است؛ آنها را در requirements.txt فهرست کنید.
  2. بدون pip install در پوشه lib ، به این معنی که دوره پوشه lib وجود ندارد
  3. عدم فهرست‌بندی کتابخانه‌های داخلی شخص ثالث (بنابراین بخش libraries وجود ندارد) در app.yaml ؛ فهرست آنها در requirements.txt
  4. عدم وجود کتابخانه‌های شخص ثالث برای ارجاع از برنامه شما به این معنی است که فایل appengine_config.py وجود ندارد.

تنها الزام توسعه‌دهنده، فهرست کردن تمام کتابخانه‌های شخص ثالث مورد نظر در requirements.txt است.

۵. به‌روزرسانی فایل‌های برنامه

فقط یک فایل برنامه، main.py ، وجود دارد، بنابراین تمام تغییرات در این بخش فقط بر آن فایل تأثیر می‌گذارند. در زیر یک تصویر "diffs" در مورد تغییرات کلی که باید برای بازسازی کد موجود در برنامه جدید ایجاد شود، آورده شده است. انتظار نمی‌رود خوانندگان کد را خط به خط بخوانند، زیرا هدف آن صرفاً دریافت یک نمای کلی تصویری از آنچه در این بازسازی مورد نیاز است، می‌باشد (اما در صورت تمایل می‌توانید آن را در یک برگه جدید باز کنید یا دانلود کرده و بزرگنمایی کنید).

5d043768ba7be742.png

به‌روزرسانی واردات و مقداردهی اولیه

بخش import در 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()

ثبت وقایع در نسل دوم زمان‌های اجرا مانند پایتون ۳ ساده‌سازی و بهبود یافته است:

  • برای تجربه جامع ثبت وقایع، از Cloud Logging استفاده کنید
  • برای گزارش‌گیری ساده، فقط کافیست از طریق print() به stdout (یا stderr ) ارسال کنید.
  • نیازی به استفاده از ماژول logging پایتون نیست (پس آن را حذف کنید)

به این ترتیب، فایل import مربوط به 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()

مهاجرت به فروشگاه داده ابری

حالا وقت آن رسیده که استفاده از کتابخانه کلاینت NDB را با Datastore جایگزین کنیم. هر دو App Engine NDB و Cloud NDB به یک مدل داده (کلاس) نیاز دارند؛ برای این برنامه، این Visit است. تابع store_visit() در تمام ماژول‌های مهاجرت دیگر به طور یکسان عمل می‌کند: این تابع با ایجاد یک رکورد Visit جدید، یک بازدید را ثبت می‌کند و آدرس IP و عامل کاربر (نوع مرورگر) کلاینت بازدیدکننده را ذخیره می‌کند.

قبل از:

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 NDB را با معادل Cloud Datastore عوض کنید؛ سبک‌های کوئری کمی متفاوت هستند.
  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

معمولاً این تمام چیزی است که لازم است. متأسفانه یک مشکل اساسی وجود دارد.

(احتمالاً) یک صف (push) جدید ایجاد کنید

در ماژول ۷، ما استفاده از taskqueue App Engine را به برنامه موجود در ماژول ۱ اضافه کردیم. یکی از مزایای کلیدی داشتن وظایف push به عنوان یک ویژگی قدیمی App Engine این است که یک صف "پیش‌فرض" به طور خودکار ایجاد می‌شود. وقتی آن برنامه در ماژول ۸ به Cloud Tasks منتقل شد، آن صف پیش‌فرض از قبل وجود داشت، بنابراین ما هنوز نیازی به نگرانی در مورد آن نداشتیم. این مورد در ماژول ۹ تغییر می‌کند.

یکی از جنبه‌های حیاتی که باید در نظر گرفته شود این است که برنامه جدید App Engine دیگر از سرویس‌های App Engine استفاده نمی‌کند و به همین دلیل، دیگر نمی‌توانید فرض کنید که App Engine به طور خودکار یک صف وظیفه را در یک محصول متفاوت (Cloud Tasks) ایجاد می‌کند. همانطور که نوشته شده است، ایجاد یک وظیفه در 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

تابع create_queue() در Cloud Tasks به نام مسیر کامل صف به جز نام صف نیاز دارد. برای سادگی، یک متغیر دیگر به نام PATH_PREFIX ایجاد کنید که نشان‌دهنده QUEUE_PATH منهای نام صف باشد ( QUEUE_PATH.rsplit('/', 2)[0] ). تعریف آن را نزدیک به بالا اضافه کنید تا بلوک کد با تمام مقادیر ثابت به این شکل باشد:

_, 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]

حالا آخرین خط در fetch_visits() را برای استفاده _create_queue_if() تغییر دهید، ابتدا در صورت لزوم صف را ایجاد کنید، سپس وظیفه را ایجاد کنید:

    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

به غیر از اضافه کردن این کد اضافی، بقیه کد Cloud Tasks تقریباً از ماژول ۸ دست نخورده باقی مانده است. آخرین قطعه کدی که باید بررسی شود، کنترل کننده وظیفه است.

به‌روزرسانی (push) کنترل‌کننده‌ی وظیفه

در تابع trim() ، کد Cloud NDB برای بازدیدهای قدیمی‌تر از قدیمی‌ترین بازدید نمایش داده شده، جستجو می‌کند. این تابع از یک جستجوی فقط کلید برای سرعت بخشیدن به کارها استفاده می‌کند - اگر فقط به شناسه‌های بازدید نیاز دارید، چرا باید همه داده‌ها را واکشی کنید؟ وقتی همه شناسه‌های بازدید را دارید، همه آنها را با تابع delete_multi() در Cloud NDB به صورت دسته‌ای حذف کنید.

قبل از:

@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 NDB با Cloud Datastore، اصلاح سبک‌های پرس‌وجو، حذف استفاده از context manager آن و تغییر فراخوانی‌های ثبت وقایع به 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() ایجاد نشده است.

پورت کردن به پایتون ۳

این برنامه نمونه برای اجرا روی هر دو نسخه پایتون ۲ و ۳ طراحی شده است. هرگونه تغییر خاص پایتون ۳ قبلاً در بخش‌های مربوطه این آموزش پوشش داده شده است. هیچ مرحله اضافی یا کتابخانه سازگاری لازم نیست.

به‌روزرسانی وظایف ابری

نسخه نهایی کتابخانه کلاینت Cloud Tasks که از پایتون ۲ پشتیبانی می‌کند، ۱.۵.۰ است. در زمان نگارش این مطلب، آخرین نسخه کتابخانه کلاینت برای پایتون ۳ کاملاً با آن نسخه سازگار است، بنابراین نیازی به به‌روزرسانی بیشتر نیست.

به‌روزرسانی قالب HTML

هیچ تغییری در فایل قالب HTML، templates/index.html ، نیز لازم نیست، بنابراین این تمام تغییرات لازم برای رسیدن به برنامه ماژول ۹ را جمع‌بندی می‌کند.

۶. خلاصه/پاکسازی

استقرار و تأیید برنامه

پس از اتمام به‌روزرسانی‌های کد، عمدتاً پورت به پایتون ۳، برنامه خود را با gcloud app deploy مستقر کنید. خروجی باید مشابه برنامه‌های ماژول‌های ۷ و ۸ باشد، با این تفاوت که دسترسی به پایگاه داده را به کتابخانه کلاینت Cloud Datastore منتقل کرده و به پایتون ۳ ارتقا داده‌اید:

ماژول ۷ اپلیکیشن visitme

این مرحله codelab را تکمیل می‌کند. از شما دعوت می‌کنیم کد خود را با آنچه در پوشه Module 9 است مقایسه کنید. تبریک می‌گوییم!

تمیز کردن

عمومی

اگر فعلاً کارتان تمام است، توصیه می‌کنیم برنامه App Engine خود را غیرفعال کنید تا از پرداخت هزینه جلوگیری شود. با این حال، اگر می‌خواهید بیشتر آزمایش یا تجربه کنید، پلتفرم App Engine سهمیه رایگان دارد و بنابراین تا زمانی که از آن سطح استفاده تجاوز نکنید، نباید هزینه‌ای از شما دریافت شود. این هزینه برای محاسبات است، اما ممکن است برای سرویس‌های مربوطه App Engine نیز هزینه‌هایی وجود داشته باشد، بنابراین برای اطلاعات بیشتر به صفحه قیمت‌گذاری آن مراجعه کنید. اگر این مهاجرت شامل سایر سرویس‌های ابری باشد، هزینه آنها جداگانه محاسبه می‌شود. در هر صورت، در صورت لزوم، به بخش "ویژه این codelab" در زیر مراجعه کنید.

برای روشن شدن کامل موضوع، استقرار در یک پلتفرم محاسباتی بدون سرور Google Cloud مانند App Engine هزینه‌های ساخت و ذخیره‌سازی کمی را متحمل می‌شود. Cloud Build نیز مانند Cloud Storage سهمیه رایگان خود را دارد. ذخیره‌سازی آن تصویر مقداری از آن سهمیه را مصرف می‌کند. با این حال، ممکن است در منطقه‌ای زندگی کنید که چنین ردیف رایگانی ندارد، بنابراین برای به حداقل رساندن هزینه‌های احتمالی، از میزان استفاده از فضای ذخیره‌سازی خود آگاه باشید. «پوشه‌های» خاص 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 *ation شما بستگی دارند، برای مثال، اگر برنامه شما در ایالات متحده میزبانی می‌شود، " us " خواهد بود.

از طرف دیگر، اگر قصد ندارید با این برنامه یا سایر آزمایشگاه‌های کد مهاجرت مرتبط ادامه دهید و می‌خواهید همه چیز را به طور کامل حذف کنید، پروژه خود را ببندید .

مخصوص این آزمایشگاه کد

سرویس‌های ذکر شده در زیر مختص این codelab هستند. برای اطلاعات بیشتر به مستندات هر محصول مراجعه کنید:

مراحل بعدی

بدین ترتیب، مهاجرت ما از وظایف ارسالی App Engine Task Queue به Cloud Tasks به پایان می‌رسد. مهاجرت اختیاری از Cloud NDB به Cloud Datastore نیز به طور جداگانه (بدون Task Queue یا Cloud Tasks) در ماژول 3 پوشش داده شده است. علاوه بر ماژول 3، ماژول‌های مهاجرت دیگری نیز وجود دارند که بر فاصله گرفتن از سرویس‌های همراه قدیمی App Engine تمرکز دارند که باید در نظر گرفته شوند، از جمله:

App Engine دیگر تنها پلتفرم بدون سرور در Google Cloud نیست. اگر یک برنامه کوچک App Engine یا برنامه‌ای با قابلیت‌های محدود دارید و می‌خواهید آن را به یک میکروسرویس مستقل تبدیل کنید، یا می‌خواهید یک برنامه یکپارچه را به چندین مؤلفه قابل استفاده مجدد تقسیم کنید، اینها دلایل خوبی برای در نظر گرفتن انتقال به Cloud Functions هستند. اگر کانتینرسازی به بخشی از گردش کار توسعه برنامه شما تبدیل شده است، به خصوص اگر شامل یک خط لوله CI/CD (ادغام مداوم/تحویل مداوم یا استقرار) باشد، مهاجرت به Cloud Run را در نظر بگیرید. این سناریوها توسط ماژول‌های زیر پوشش داده می‌شوند:

  • مهاجرت از موتور برنامه به توابع ابری: به ماژول 11 مراجعه کنید
  • مهاجرت از App Engine به Cloud Run: برای کانتینرایز کردن برنامه خود با Docker به ماژول ۴ و برای انجام این کار بدون کانتینرها، دانش Docker یا Dockerfile ها به ماژول ۵ مراجعه کنید.

تغییر به یک پلتفرم بدون سرور دیگر اختیاری است و توصیه می‌کنیم قبل از ایجاد هرگونه تغییر، بهترین گزینه‌ها را برای برنامه‌ها و موارد استفاده خود در نظر بگیرید.

صرف نظر از اینکه کدام ماژول مهاجرت را در مرحله بعد در نظر بگیرید، تمام محتوای Serverless Migration Station (آزمایشگاه‌های کد، ویدیوها، کد منبع [در صورت وجود]) در مخزن متن‌باز آن قابل دسترسی است. README این مخزن همچنین راهنمایی‌هایی در مورد اینکه کدام مهاجرت‌ها را باید در نظر گرفت و هرگونه «ترتیب» مربوط به ماژول‌های مهاجرت ارائه می‌دهد.

۷. منابع اضافی

مشکلات/بازخوردهای Codelabs

اگر در این آزمایشگاه کد مشکلی پیدا کردید، لطفاً قبل از ثبت، ابتدا مشکل خود را جستجو کنید. لینک‌های جستجو و ایجاد مشکلات جدید:

منابع مهاجرت

لینک‌های پوشه‌های مخزن ماژول ۸ (START) و ماژول ۹ (FINISH) را می‌توانید در جدول زیر پیدا کنید. همچنین می‌توانید از مخزن تمام مهاجرت‌های Codelab مربوط به App Engine که می‌توانید آن‌ها را کلون کنید یا یک فایل ZIP دانلود کنید، به آن‌ها دسترسی داشته باشید.

کدلب

پایتون ۲

پایتون ۳

ماژول ۸

کد

(نامشخص)

ماژول ۹

(نامشخص)

کد

منابع آنلاین

در زیر منابع آنلاینی وجود دارد که ممکن است برای این آموزش مرتبط باشند:

موتور برنامه

ابر NDB

فروشگاه داده ابری

وظایف ابری

سایر اطلاعات ابری

مجوز

این اثر تحت مجوز عمومی Creative Commons Attribution 2.0 منتشر شده است.