نحوه استفاده از App Engine Task Queue (وظایف فشاری) در برنامه های Flask (ماژول 7)

۱. مرور کلی

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

این آزمایشگاه کد به شما آموزش می‌دهد که چگونه از وظایف ارسالی App Engine Task Queue در برنامه نمونه از آزمایشگاه کد ماژول ۱ استفاده کنید. پست وبلاگ و ویدیوی ماژول ۷ این آموزش را تکمیل می‌کنند و خلاصه‌ای از محتوای این آموزش را ارائه می‌دهند.

در این ماژول، استفاده از وظایف push را اضافه خواهیم کرد، سپس آن کاربرد را به Cloud Tasks در ماژول 8 و بعداً به پایتون 3 و Cloud Datastore در ماژول 9 منتقل خواهیم کرد. کسانی که از Task Queues برای وظایف pull استفاده می‌کنند، به Cloud Pub/Sub مهاجرت می‌کنند و باید به ماژول‌های 18-19 مراجعه کنند.

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

  • از API/سرویس همراه App Engine Task Queue استفاده کنید
  • افزودن میزان استفاده از وظایف ارسالی به یک برنامه پایه Python 2 Flask App Engine NDB

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

نظرسنجی

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

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

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

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

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

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

۲. پیشینه

صف وظایف موتور برنامه از هر دو وظیفه push و pull پشتیبانی می‌کند. برای بهبود قابلیت حمل برنامه، تیم Google Cloud توصیه می‌کند از سرویس‌های قدیمی مانند Task Queue به سایر سرویس‌های مستقل Cloud یا معادل‌های شخص ثالث مهاجرت کنید.

مهاجرت وظیفه‌ی Pull در ماژول‌های مهاجرت ۱۸-۱۹ پوشش داده شده است، در حالی که ماژول‌های ۷-۹ بر مهاجرت وظیفه‌ی Push تمرکز دارند. برای مهاجرت از وظایف Push صف وظیفه‌ی App Engine، کاربرد آن را به برنامه‌ی Flask و App Engine NDB موجود حاصل از codelab ماژول ۱ اضافه کنید. در آن برنامه، یک نمای صفحه‌ی جدید، یک بازدید جدید را ثبت می‌کند و جدیدترین بازدیدها را به کاربر نمایش می‌دهد. از آنجایی که بازدیدهای قدیمی‌تر دیگر هرگز نشان داده نمی‌شوند و فضایی را در Datastore اشغال می‌کنند، ما قصد داریم یک وظیفه‌ی Push ایجاد کنیم تا به طور خودکار قدیمی‌ترین بازدیدها را حذف کند. در ادامه در ماژول ۸، آن برنامه را از صف وظیفه به Cloud Tasks منتقل خواهیم کرد.

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

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

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

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

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

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

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

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

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

یکی از پیش‌نیازهای این آزمایشگاه کد، داشتن یک برنامه ماژول ۱ App Engine است: آزمایشگاه کد ماژول ۱ (توصیه می‌شود) را تکمیل کنید یا برنامه ماژول ۱ را از مخزن کپی کنید. چه از کد خودتان استفاده کنید و چه از کد ما، کد ماژول ۱ جایی است که ما "شروع" می‌کنیم. این آزمایشگاه کد شما را در هر مرحله راهنمایی می‌کند و با کدی که شبیه کد موجود در پوشه مخزن ماژول ۷ "FINISH" است، به پایان می‌رساند.

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

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

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

برای (دوباره) استقرار برنامه ماژول ۱، مراحل زیر را اجرا کنید:

  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. تأیید کنید که برنامه ماژول ۱ طبق انتظار و بدون مشکل در نمایش آخرین بازدیدها اجرا می‌شود (در زیر نشان داده شده است)

a7a9d2b80d706a2b.png

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

هیچ تغییری در فایل‌های پیکربندی استاندارد App Engine ( app.yaml ، requirements.txt ، appengine_config.py ) لازم نیست.

۵. فایل‌های برنامه را تغییر دهید

فایل اصلی برنامه main.py است و تمام به‌روزرسانی‌های این بخش مربوط به آن فایل است. همچنین یک به‌روزرسانی جزئی در قالب وب، templates/index.html ، وجود دارد. اینها تغییراتی هستند که باید در این بخش پیاده‌سازی شوند:

  1. به‌روزرسانی واردات
  2. اضافه کردن وظیفه فشاری
  3. اضافه کردن کنترل کننده وظایف
  4. قالب وب را به‌روزرسانی کنید

۱. به‌روزرسانی ایمپورت‌ها

وارد کردن google.appengine.api.taskqueue قابلیت Task Queue را به ارمغان می‌آورد. برخی از بسته‌های کتابخانه استاندارد پایتون نیز مورد نیاز هستند:

  • از آنجا که ما در حال اضافه کردن وظیفه‌ای برای حذف قدیمی‌ترین بازدیدها هستیم، برنامه باید با مهرهای زمانی، یعنی استفاده از time و datetime سر و کار داشته باشد.
  • برای ثبت اطلاعات مفید در مورد اجرای وظیفه، logging نیاز داریم.

با اضافه کردن همه این ایمپورت‌ها، کد شما قبل و بعد از این تغییرات به صورت زیر خواهد بود:

قبل از:

from flask import Flask, render_template, request
from google.appengine.ext import ndb

بعد از:

from datetime import datetime
import logging
import time
from flask import Flask, render_template, request
from google.appengine.api import taskqueue
from google.appengine.ext import ndb

۲. اضافه کردن وظیفه‌ی ارسالی (جمع‌آوری داده‌ها برای وظیفه، قرار دادن وظیفه‌ی جدید در صف)

مستندات صف ارسال اظهار می‌کند: «برای پردازش یک وظیفه، باید آن را به یک صف ارسال اضافه کنید. App Engine یک صف ارسال پیش‌فرض به نام default ارائه می‌دهد که پیکربندی شده و با تنظیمات پیش‌فرض آماده استفاده است. در صورت تمایل، می‌توانید تمام وظایف خود را بدون نیاز به ایجاد و پیکربندی صف‌های دیگر، به صف پیش‌فرض اضافه کنید.» این codelab برای اختصار از صف default استفاده می‌کند. برای کسب اطلاعات بیشتر در مورد تعریف صف‌های ارسال خودتان، با ویژگی‌های یکسان یا متفاوت، به مستندات Creating Push Queues مراجعه کنید.

The primary goal of this codelab is to add a task (to the default push queue) whose job it is to delete old visits from Datastore that are no longer displayed. The baseline app registers each visit ( GET request to / ) by creating a new Visit entity, then fetches and displays the most recent visits. None of the oldest visits will ever be displayed or used again, so the push task deletes all visits older than the oldest displayed . To accomplish this, the app's behavior needs to change a bit:

  1. هنگام جستجوی جدیدترین بازدیدها، به جای بازگرداندن فوری آن بازدیدها، برنامه را طوری تغییر دهید که مهر زمانی آخرین Visit ، قدیمی‌ترین بازدید نمایش داده شده، را ذخیره کند - حذف همه بازدیدهای قدیمی‌تر از این تاریخ بی‌خطر است.
  2. یک وظیفه‌ی پوش (push task) با این مهر زمانی به عنوان بار داده (payload) آن ایجاد کنید و آن را به کنترل‌کننده‌ی وظیفه (task handler) که از طریق HTTP POST به /trim قابل دسترسی است، هدایت کنید. به طور خاص، از ابزارهای استاندارد پایتون برای تبدیل مهر زمانی Datastore و ارسال آن (به عنوان یک عدد اعشاری) به وظیفه و همچنین ثبت آن (به عنوان یک رشته) و بازگرداندن آن رشته به عنوان یک مقدار نگهبان (sentinel value) برای نمایش به کاربر استفاده کنید.

همه این اتفاقات در fetch_visits() رخ می‌دهد و این همان چیزی است که قبل و بعد از انجام این به‌روزرسانی‌ها به نظر می‌رسد:

قبل از:

def fetch_visits(limit):
    return (v.to_dict() for v in Visit.query().order(
            -Visit.timestamp).fetch(limit))

بعد از:

def fetch_visits(limit):
    'get most recent visits and add task to delete older visits'
    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)
    taskqueue.add(url='/trim', params={'oldest': oldest})
    return (v.to_dict() for v in data), oldest_str

۳. اضافه کردن task handler (کدی که هنگام اجرای task فراخوانی می‌شود)

اگرچه حذف بازدیدهای قدیمی می‌توانست به راحتی در fetch_visits() انجام شود، اما توجه داشته باشید که این قابلیت ارتباط زیادی با کاربر نهایی ندارد. این یک قابلیت کمکی است و کاندیدای خوبی برای پردازش ناهمگام خارج از درخواست‌های استاندارد برنامه است. کاربر نهایی از مزایای پرس‌وجوهای سریع‌تر بهره‌مند خواهد شد زیرا اطلاعات کمتری در Datastore وجود خواهد داشت. یک تابع جدید trim() ایجاد کنید که از طریق یک درخواست POST صف وظایف به /trim فراخوانی می‌شود و موارد زیر را انجام می‌دهد:

  1. بار داده‌ی برچسب زمانی «قدیمی‌ترین بازدید» را استخراج می‌کند.
  2. یک کوئری Datastore برای یافتن تمام موجودیت‌های قدیمی‌تر از آن برچسب زمانی صادر می‌کند.
  3. به دلیل عدم نیاز به داده‌های واقعی کاربر، یک پرس‌وجوی سریع‌تر «فقط کلیدها» را انتخاب می‌کند.
  4. تعداد موجودیت‌هایی که باید حذف شوند (شامل صفر) را ثبت می‌کند.
  5. تابع ndb.delete_multi() را برای حذف هر موجودیتی فراخوانی می‌کند (در غیر این صورت، از آن صرف نظر می‌شود).
  6. یک رشته خالی (همراه با یک کد بازگشتی ضمنی HTTP 200) را برمی‌گرداند.

می‌توانید همه این موارد را در trim() زیر مشاهده کنید. آن را درست بعد از fetch_visits() به main.py اضافه کنید:

@app.route('/trim', methods=['POST'])
def trim():
    '(push) task queue handler to delete oldest visits'
    oldest = request.form.get('oldest', type=float)
    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

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

قالب وب، templates/index.html ، را با استفاده از شرط Jinja2 به‌روزرسانی کنید تا در صورت وجود متغیر، قدیمی‌ترین برچسب زمانی نمایش داده شود:

{% if oldest is defined %}
    <b>Deleting visits older than:</b> {{ oldest }}</p>
{% endif %}

این قطعه کد را بعد از لیست بازدیدهای نمایش داده شده اما قبل از بستن بدنه اضافه کنید تا قالب شما به این شکل درآید:

<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
<body>

<h1>VisitMe example</h1>
<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
    <li>{{ visit.timestamp.ctime() }} from {{ visit.visitor }}</li>
{% endfor %}
</ul>

{% if oldest is defined %}
    <b>Deleting visits older than:</b> {{ oldest }}</p>
{% endif %}
</body>
</html>

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

این بخش، این آزمایشگاه کد را با استقرار برنامه، تأیید عملکرد آن طبق برنامه و در هر خروجی منعکس‌شده، به پایان می‌رساند. پس از اعتبارسنجی برنامه، هرگونه پاکسازی را انجام داده و مراحل بعدی را در نظر بگیرید.

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

برنامه را با استفاده از gcloud app deploy مستقر کنید. خروجی باید مشابه برنامه ماژول ۱ باشد، به جز یک خط جدید در پایین که نشان می‌دهد کدام بازدیدها حذف خواهند شد:

4aa8a2cb5f527079.png

تبریک می‌گویم که آزمایشگاه کد را تکمیل کردید. کد شما اکنون باید با آنچه در پوشه مخزن ماژول ۷ است، مطابقت داشته باشد. اکنون آماده انتقال به Cloud Tasks در ماژول ۸ است.

تمیز کردن

عمومی

اگر فعلاً کارتان تمام است، توصیه می‌کنیم برنامه 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 هستند. برای اطلاعات بیشتر به مستندات هر محصول مراجعه کنید:

مراحل بعدی

در این «مهاجرت»، شما استفاده از صف ارسال Task Queue را به برنامه نمونه ماژول ۱ اضافه کردید و پشتیبانی از ردیابی بازدیدکنندگان را نیز به آن اضافه کردید که منجر به برنامه نمونه ماژول ۷ شد. مهاجرت بعدی به شما آموزش می‌دهد که در صورت تمایل، چگونه از وظایف ارسالی App Engine به Cloud Tasks ارتقا دهید. از پاییز ۲۰۲۱، کاربران دیگر نیازی به مهاجرت به Cloud Tasks هنگام ارتقا به پایتون ۳ ندارند. در بخش بعدی درباره این موضوع بیشتر بخوانید.

اگر می‌خواهید به Cloud Tasks منتقل شوید، Codelab ماژول ۸ گزینه بعدی است. فراتر از آن، مهاجرت‌های اضافی دیگری مانند Cloud Datastore، Cloud Memorystore، Cloud Storage یا Cloud Pub/Sub (صف‌های pull) نیز باید در نظر گرفته شوند. همچنین مهاجرت‌های بین محصولی به Cloud Run و Cloud Functions نیز وجود دارد. به تمام محتوای Serverless Migration Station (آزمایشگاه‌های کد، ویدیوها، کد منبع [در صورت وجود]) می‌توان در مخزن متن‌باز آن دسترسی پیدا کرد.

۷. مهاجرت به پایتون ۳

در پاییز ۲۰۲۱، تیم App Engine پشتیبانی از بسیاری از سرویس‌های همراه را به Runtimeهای نسل دوم (که در ابتدا فقط در Runtimeهای نسل اول موجود بودند) گسترش داد ، به این معنی که دیگر نیازی نیست هنگام انتقال برنامه خود به پایتون ۳، از سرویس‌های همراه مانند App Engine Task Queue به Cloud مستقل یا معادل‌های شخص ثالث مانند Cloud Tasks مهاجرت کنید. به عبارت دیگر، می‌توانید به استفاده از Task Queue در برنامه‌های App Engine پایتون ۳ ادامه دهید، مادامی که کد را برای دسترسی به سرویس‌های همراه از Runtimeهای نسل بعدی، به‌روزرسانی کنید.

می‌توانید در مورد نحوه انتقال استفاده از سرویس‌های همراه به پایتون ۳ در codelab ماژول ۱۷ و ویدیوی مربوطه اطلاعات بیشتری کسب کنید. اگرچه این موضوع خارج از محدوده ماژول ۷ است، اما لینک‌های زیر نسخه‌های پایتون ۳ از هر دو برنامه ماژول ۱ و ۷ را نشان می‌دهند که به پایتون ۳ منتقل شده‌اند و هنوز از App Engine NDB و Task Queue استفاده می‌کنند.

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

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

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

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

منابع مهاجرت

لینک‌های پوشه‌های مخزن ماژول ۲ (START) و ماژول ۷ (FINISH) را می‌توانید در جدول زیر بیابید.

کدلب

پایتون ۲

پایتون ۳

ماژول ۱

کد

کد (در این آموزش نمایش داده نشده است)

ماژول ۷ (این آزمایشگاه کد)

کد

کد (در این آموزش نمایش داده نشده است)

منابع آنلاین

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

صف وظایف موتور برنامه

پلتفرم موتور برنامه

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

ویدیوها

مجوز

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