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

1. بررسی اجمالی

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

این کد لبه به شما می آموزد که چگونه از وظایف فشاری App Engine Task Queue در برنامه نمونه از ماژول 1 Codelab استفاده کنید. پست وبلاگ و ویدیوی ماژول 7 مکمل این آموزش است و یک نمای کلی از محتوای این آموزش ارائه می دهد.

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

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

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

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

نظرسنجی

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

فقط از طریق آن را بخوانید آن را بخوانید و تمرینات را کامل کنید

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

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

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

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

2. پس زمینه

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

انتقال وظیفه کششی در ماژول های مهاجرت 18-19 پوشش داده شده است در حالی که ماژول های 7-9 بر مهاجرت وظیفه فشاری تمرکز دارند. به منظور انتقال از وظایف فشاری App Engine Task Queue، استفاده از آن را به برنامه موجود Flask و App Engine NDB حاصل از کد ماژول 1 اضافه کنید. در آن برنامه، یک نمای صفحه جدید، یک بازدید جدید را ثبت می کند و آخرین بازدیدها را به کاربر نمایش می دهد. از آنجایی که بازدیدهای قدیمی‌تر دیگر هرگز نشان داده نمی‌شوند و فضایی را در Datastore اشغال می‌کنند، می‌خواهیم یک وظیفه فشار ایجاد کنیم تا به‌طور خودکار قدیمی‌ترین بازدیدها حذف شود. در ماژول 8، آن برنامه را از Task Queue به Cloud Tasks منتقل می کنیم.

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

  1. راه اندازی/پیش کار
  2. پیکربندی را به روز کنید
  3. کد برنامه را تغییر دهید

3. راه اندازی/پیش کار

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

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

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

1. پروژه راه اندازی

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

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

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

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

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

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

مراحل زیر را برای استقرار مجدد برنامه ماژول 1 انجام دهید:

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

a7a9d2b80d706a2b.png

4. پیکربندی را به روز کنید

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

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

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

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

1. واردات را به روز کنید

وارد کردن 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

2. اضافه کردن وظیفه فشار (ترکیب داده ها برای کار، صف بندی کار جدید)

در اسناد push queue آمده است: "برای پردازش یک کار، باید آن را به یک صف فشار اضافه کنید. App Engine یک صف فشار پیش‌فرض با نام default ارائه می‌کند که پیکربندی شده و آماده استفاده با تنظیمات پیش‌فرض است. اگر می‌خواهید، فقط می‌توانید بدون نیاز به ایجاد و پیکربندی صف های دیگر، تمام وظایف خود را به صف پیش فرض اضافه کنید." این کد لبه از صف default برای اختصار استفاده می کند. برای کسب اطلاعات بیشتر در مورد تعریف صف های فشار خود، با ویژگی های یکسان یا متفاوت، به مستندات ایجاد صف های فشار مراجعه کنید.

هدف اصلی این کد لبه اضافه کردن یک وظیفه (به صف فشار default ) است که وظیفه آن حذف بازدیدهای قدیمی از Datastore است که دیگر نمایش داده نمی‌شوند. برنامه پایه هر بازدید (درخواست GET به / ) را با ایجاد یک موجودیت Visit جدید ثبت می‌کند، سپس آخرین بازدیدها را واکشی و نمایش می‌دهد. هیچ‌یک از قدیمی‌ترین بازدیدها هرگز نمایش داده نمی‌شود یا دوباره استفاده نمی‌شود، بنابراین وظیفه فشاری همه بازدیدهای قدیمی‌تر از قدیمی‌ترین بازدیدهای نمایش داده شده را حذف می‌کند . برای انجام این کار، رفتار برنامه باید کمی تغییر کند:

  1. هنگامی که آخرین بازدیدها را پرس و جو می کنید، به جای اینکه آن بازدیدها را فوراً بازگردانید، برنامه را طوری تغییر دهید که مُهر زمانی آخرین Visit ، قدیمی‌ترین بازدید نمایش داده شده، ذخیره شود — پاک کردن تمام بازدیدهای قدیمی‌تر از این امن است.
  2. یک وظیفه فشاری با این مهر زمانی به عنوان بار آن ایجاد کنید و آن را به کنترل کننده وظیفه هدایت کنید، که از طریق یک HTTP POST به /trim قابل دسترسی است. به طور خاص، از ابزارهای استاندارد پایتون برای تبدیل مهر زمانی Datastore و ارسال آن (به عنوان شناور) به وظیفه استفاده کنید، اما همچنین آن را ثبت کنید (به عنوان یک رشته) و آن رشته را به عنوان یک مقدار نگهبان برای نمایش به کاربر برگردانید.

همه اینها در 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

3. کنترل کار را اضافه کنید (کد هنگام اجرای کار فراخوانی می شود)

در حالی که حذف بازدیدهای قدیمی می‌توانست به راحتی در fetch_visits() انجام شود، بدانید که این عملکرد ارتباط زیادی با کاربر نهایی ندارد. این عملکرد کمکی است و کاندیدای خوبی برای پردازش غیرهمزمان خارج از درخواست های برنامه استاندارد است. کاربر نهایی از پرس و جوهای سریعتر بهره خواهد برد زیرا اطلاعات کمتری در Datastore وجود خواهد داشت. یک تابع جدید trim() ایجاد کنید که از طریق یک درخواست Task Queue 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

4. قالب وب را به روز کنید

الگوی وب، 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>

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

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

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

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

4aa8a2cb5f527079.png

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

تمیز کردن

ژنرال

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

برای افشای کامل، استقرار در یک پلت فرم محاسباتی بدون سرور 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 * شما بستگی دارد، به عنوان مثال، اگر برنامه شما در ایالات متحده میزبانی می شود، " us ".

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

مخصوص این کد لبه

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

مراحل بعدی

در این «مهاجرت»، استفاده از صف فشار Task Queue را به برنامه نمونه ماژول 1 اضافه کردید، و پشتیبانی برای ردیابی بازدیدکنندگان را اضافه کردید که نتیجه آن برنامه نمونه ماژول 7 شد. انتقال بعدی به شما می آموزد که در صورت انتخاب این کار، چگونه از App Engine push tasks به Cloud Tasks ارتقا دهید. از پاییز 2021، کاربران دیگر نیازی به مهاجرت به Cloud Tasks در هنگام ارتقا به Python 3 ندارند. در بخش بعدی در مورد این موضوع بیشتر بخوانید.

اگر می‌خواهید به Cloud Tasks بروید، کد ماژول 8 بعدی است. فراتر از آن باید مهاجرت‌های بیشتری را در نظر گرفت، مانند Cloud Datastore، Cloud Memorystore، Cloud Storage یا Cloud Pub/Sub (صف‌های کششی). همچنین انتقال محصول متقابل به Cloud Run و Cloud Function وجود دارد. تمام محتوای ایستگاه مهاجرت بدون سرور (مجموعه‌های کد، ویدیوها، کد منبع [در صورت وجود]) را می‌توان در مخزن منبع باز آن مشاهده کرد.

7. مهاجرت به پایتون 3

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

می‌توانید در مورد نحوه انتقال استفاده از سرویس‌های همراه به پایتون 3 در ماژول 17 و ویدیوی مربوط به آن اطلاعات بیشتری کسب کنید. در حالی که این موضوع برای ماژول 7 خارج از محدوده است، لینک زیر نسخه های Python 3 هر دو برنامه ماژول 1 و 7 است که به پایتون 3 منتقل شده اند و همچنان از App Engine NDB و Task Queue استفاده می کنند.

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

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

مسائل/بازخوردهای Codelab

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

منابع مهاجرت

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

Codelab

پایتون 2

پایتون 3

ماژول 1

کد

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

ماژول 7 (این نرم افزار کد)

کد

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

منابع آنلاین

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

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

پلت فرم App Engine

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

ویدیوها

مجوز

این اثر تحت مجوز Creative Commons Attribution 2.0 Generic مجوز دارد.