كيفية استخدام قائمة انتظار مهام App Engine (الإشعارات الفورية) في تطبيقات Flask (الوحدة 7)

1. نظرة عامة

تهدف سلسلة البرامج التعليمية حول Serverless Migration Station (برامج تعليمية ذاتية السرعة وعملية) ومقاطع الفيديو ذات الصلة إلى مساعدة مطوّري الحوسبة بدون خادم على Google Cloud في تحديث تطبيقاتهم من خلال إرشادهم خلال عملية نقل واحدة أو أكثر، مع التركيز بشكل أساسي على التخلّي عن الخدمات القديمة. يؤدي ذلك إلى زيادة قابلية نقل تطبيقاتك ويمنحك المزيد من الخيارات والمرونة، ما يتيح لك الدمج مع مجموعة أكبر من منتجات Cloud والوصول إليها، كما يسهّل عليك الترقية إلى أحدث إصدارات اللغة. على الرغم من أنّ هذه السلسلة تركّز في البداية على أوائل مستخدمي Cloud، وخاصةً مطوّري App Engine (البيئة العادية)، إلا أنّها واسعة النطاق بما يكفي لتشمل منصات أخرى بلا خادم، مثل Cloud Functions وCloud Run، أو في أي مكان آخر إذا كان ذلك منطبقًا.

يعلّمك هذا الدرس التطبيقي حول الترميز كيفية استخدام مهام الدفع في "قائمة انتظار المهام" في App Engine في نموذج التطبيق من الدرس التطبيقي حول الترميز في الوحدة 1. تُكمّل مشاركة المدوّنة والفيديو في الوحدة 7 هذا البرنامج التعليمي، إذ تقدّم نظرة عامة موجزة على المحتوى الوارد فيه.

في هذه الوحدة، سنضيف استخدام مهام الدفع، ثم ننقل هذا الاستخدام إلى Cloud Tasks في الوحدة 8، ثم إلى Python 3 وCloud Datastore في الوحدة 9. سيتم نقل المستخدمين الذين يستعينون بـ "قوائم انتظار المهام" لتنفيذ مهام السحب إلى Cloud Pub/Sub، وعليهم الرجوع إلى الوحدتين 18 و19 بدلاً من ذلك.

ستتعرَّف على كيفية إجراء ما يلي:

  • استخدام واجهة برمجة التطبيقات/الخدمة المجمّعة "قائمة مهام App Engine"
  • إضافة استخدام مهام الدفع إلى تطبيق أساسي يستند إلى Python 2 Flask App Engine NDB

المتطلبات

استطلاع الرأي

كيف ستستخدم هذا البرنامج التعليمي؟

قراءة المحتوى فقط قراءة المحتوى وإكمال التمارين

كيف تقيّم تجربتك مع Python؟

مبتدئ متوسط متمكّن

ما هو تقييمك لتجربة استخدام خدمات Google Cloud؟

مبتدئ متوسط متقدّم

2. الخلفية

تتيح قائمة انتظار المهام في App Engine مهام الدفع والسحب. لتحسين إمكانية نقل التطبيقات، ينصح فريق Google Cloud بالانتقال من الخدمات المجمّعة القديمة، مثل Task Queue، إلى خدمات أخرى مستقلة أو خدمات مكافئة تابعة لجهات خارجية.

يتم تناول عملية نقل المهام من خلال السحب في الوحدتين 18 و19، بينما تركّز الوحدات من 7 إلى 9 على عملية نقل المهام من خلال الدفع. لإجراء عملية نقل البيانات من مهام الدفع في "قائمة انتظار المهام" في App Engine، أضِف استخدامها إلى تطبيق Flask وApp Engine NDB الحالي الناتج عن الدرس التطبيقي حول الترميز 1. في هذا التطبيق، تسجّل مشاهدة صفحة على الويب زيارة جديدة وتعرض أحدث الزيارات للمستخدم. بما أنّ الزيارات القديمة لا تظهر مرة أخرى أبدًا وتشغل مساحة في Datastore، سننشئ مهمة دفع لحذف أقدم الزيارات تلقائيًا. في الوحدة 8، سننقل هذا التطبيق من "قائمة انتظار المهام" إلى Cloud Tasks.

يتضمّن هذا الدليل التعليمي الخطوات التالية:

  1. الإعداد/العمل التحضيري
  2. تعديل الإعدادات
  3. تعديل الرمز البرمجي للتطبيق

3- الإعداد/العمل التحضيري

يوضّح هذا القسم كيفية تنفيذ ما يلي:

  1. إعداد مشروعك على السحابة الإلكترونية
  2. الحصول على نموذج تطبيق أساسي
  3. (إعادة) نشر تطبيق أساسي وإثبات صحته

تضمن لك هذه الخطوات البدء برمز برمجي صالح.

1. إعداد المشروع

إذا أكملت الدرس التطبيقي حول الترميز Module 1، ننصحك بإعادة استخدام المشروع (والرمز) نفسه. يمكنك بدلاً من ذلك إنشاء مشروع جديد تمامًا أو إعادة استخدام مشروع حالي آخر. تأكَّد من أنّ المشروع يتضمّن حساب فوترة نشطًا وأنّ خدمة App Engine مفعَّلة.

2. الحصول على نموذج تطبيق أساسي

من المتطلبات الأساسية لهذا الدرس التطبيقي حول الترميز أن يكون لديك تطبيق يعمل على الوحدة 1 من App Engine: أكمل الدرس التطبيقي حول الترميز الخاص بالوحدة 1 (يُنصح بذلك) أو انسخ تطبيق الوحدة 1 من المستودع. سواء استخدمت رمزك أو رمزنا، سيكون رمز الوحدة 1 هو المكان الذي سنبدأ منه. يرشدك هذا الدرس التطبيقي حول الترميز خلال كل خطوة، وينتهي برمز يشبه الرمز الموجود في مجلد المستودع "FINISH" في الوحدة 7.

بغض النظر عن تطبيق الوحدة 1 الذي تستخدمه، من المفترض أن يبدو المجلد كما هو موضّح أدناه، وربما يتضمّن مجلد lib أيضًا:

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

3- (إعادة) نشر التطبيق الأساسي

نفِّذ الخطوات التالية لإعادة نشر تطبيق الوحدة 1:

  1. احذف المجلد lib إذا كان متوفّرًا ونفِّذ الأمر: pip install -t lib -r requirements.txt لإعادة ملء lib. قد تحتاج إلى استخدام الأمر pip2 بدلاً من ذلك إذا كان لديك كل من Python 2 و3 مثبّتَين.
  2. تأكَّد من أنّك ثبَّت وبدأت استخدام أداة سطر الأوامر gcloud وراجعت طريقة استخدامها.
  3. اضبط مشروعك على Cloud باستخدام gcloud config set project PROJECT_ID إذا كنت لا تريد إدخال PROJECT_ID مع كل أمر gcloud يتم إصداره.
  4. نشر نموذج التطبيق باستخدام gcloud app deploy
  5. تأكَّد من أنّ تطبيق الوحدة 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 إلى إتاحة وظائف "قائمة المهام". بعض حِزم مكتبة Python العادية مطلوبة أيضًا:

  • بما أنّنا نضيف مهمة لحذف الزيارات الأقدم، سيحتاج التطبيق إلى التعامل مع الطوابع الزمنية، ما يعني استخدام 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. إضافة مهمة دفع (تجميع البيانات للمهمة، إضافة مهمة جديدة إلى قائمة الانتظار)

توضّح مستندات قائمة انتظار الإشعارات الفورية ما يلي: "لمعالجة مهمة، يجب إضافتها إلى قائمة انتظار الإشعارات الفورية. توفّر خدمة App Engine قائمة انتظار تلقائية للدفع، واسمها default، وهي معدّة وجاهزة للاستخدام مع الإعدادات التلقائية. إذا أردت، يمكنك إضافة جميع مهامك إلى قائمة الانتظار التلقائية فقط، بدون الحاجة إلى إنشاء قوائم انتظار أخرى وإعدادها". يستخدم هذا الدرس التطبيقي حول الترميز قائمة انتظار default للاختصار. لمزيد من المعلومات عن تحديد قوائم انتظار الإشعارات الفورية الخاصة بك، مع خصائص مماثلة أو مختلفة، راجِع مستندات إنشاء قوائم انتظار الإشعارات الفورية.

الهدف الأساسي من هذا الدرس التطبيقي حول الترميز هو إضافة مهمة (إلى قائمة انتظار الدفع default) تتمثل في حذف الزيارات القديمة من مخزن البيانات التي لم يعُد يتم عرضها. يسجّل التطبيق الأساسي كل زيارة (GET طلب إلى /) من خلال إنشاء كيان Visit جديد، ثم يسترجع أحدث الزيارات ويعرضها. لن يتم عرض أي من الزيارات الأقدم أو استخدامها مرة أخرى، لذا فإنّ مهمة الدفع تحذف جميع الزيارات الأقدم من أقدم زيارة معروضة. لتحقيق ذلك، يجب تغيير سلوك التطبيق قليلاً:

  1. عند طلب البحث عن أحدث الزيارات، بدلاً من عرض هذه الزيارات على الفور، عدِّل التطبيق لحفظ الطابع الزمني لآخر Visit، وهو الأقدم الذي يتم عرضه، ويمكنك حذف جميع الزيارات الأقدم من هذا الطابع الزمني بأمان.
  2. أنشئ مهمة إرسال باستخدام هذا الطابع الزمني كحمولة موجّهة إلى معالج المهام، ويمكن الوصول إليها من خلال طلب HTTP POST إلى /trim. على وجه التحديد، استخدِم أدوات Python العادية لتحويل الطابع الزمني في 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() يتم استدعاؤها من خلال طلب POST في "قائمة انتظار المهام" إلى /trim، وتنفّذ ما يلي:

  1. يستخرج هذا الحقل حمولة الطابع الزمني "أقدم زيارة".
  2. يُصدر طلب بحث Datastore للعثور على جميع الكيانات الأقدم من هذا الطابع الزمني.
  3. يختار طلب بحث أسرع "بالمفاتيح فقط" لأنّه لا حاجة إلى بيانات المستخدم الفعلية.
  4. تسجّل هذه السمة عدد الكيانات المطلوب حذفها (بما في ذلك الصفر).
  5. استدعاء ndb.delete_multi() لحذف أي كيانات (يتم تخطّي هذه الخطوة إذا لم يكن هناك أي كيانات).
  6. تعرض هذه الدالة سلسلة فارغة (بالإضافة إلى رمز الإرجاع الضمني HTTP 200).

يمكنك الاطّلاع على كل ذلك في trim() أدناه. أضِفها إلى main.py بعد fetch_visits() مباشرةً:

@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 ذات الصلة، لذا يُرجى الاطّلاع على صفحة الأسعار للحصول على مزيد من المعلومات. إذا كان نقل البيانات هذا يتضمّن خدمات سحابية أخرى، يتم إصدار فواتير لها بشكل منفصل. في كلتا الحالتين، إذا كان ذلك منطبقًا، راجِع القسم "خاص بهذا الدرس التطبيقي حول الترميز" أدناه.

للتوضيح، يؤدي النشر على منصة حوسبة بدون خادم في 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" إذا كان تطبيقك مستضافًا في الولايات المتحدة.

من ناحية أخرى، إذا كنت لن تواصل استخدام هذا التطبيق أو غيره من الدروس التعليمية البرمجية المتعلقة بنقل البيانات وأردت حذف كل شيء تمامًا، عليك إيقاف مشروعك.

خاص بهذا الدرس التطبيقي حول الترميز

الخدمات المدرَجة أدناه خاصة بهذا الدرس التطبيقي حول الترميز. يُرجى الرجوع إلى مستندات كل منتج للحصول على مزيد من المعلومات:

الخطوات التالية

في عملية "النقل" هذه، أضفت استخدام قائمة انتظار الدفع في "قائمة انتظار المهام" إلى نموذج التطبيق في الوحدة 1، ما أدى إلى إتاحة إمكانية تتبُّع الزوّار، وبالتالي إنشاء نموذج التطبيق في الوحدة 7. تعلّمك عملية النقل التالية كيفية الترقية من مهام الدفع في App Engine إلى Cloud Tasks إذا اخترت إجراء ذلك. اعتبارًا من خريف 2021، لم يعُد على المستخدمين نقل البيانات إلى Cloud Tasks عند الترقية إلى Python 3. يمكنك الاطّلاع على مزيد من المعلومات حول هذا الموضوع في القسم التالي.

إذا كنت تريد الانتقال إلى Cloud Tasks، يمكنك الانتقال إلى درس تطبيقي حول الترميز Module 8. بالإضافة إلى ذلك، هناك عمليات نقل إضافية يجب أخذها في الاعتبار، مثل Cloud Datastore أو Cloud Memorystore أو Cloud Storage أو Cloud Pub/Sub (قوائم الانتظار). تتوفّر أيضًا عمليات نقل بيانات بين المنتجات إلى Cloud Run وCloud Functions. يمكن الوصول إلى جميع محتوى Serverless Migration Station (الدروس العملية والفيديوهات ورمز المصدر [عند توفّره]) من خلال مستودع المصدر المفتوح.

7. النقل إلى Python 3

في خريف 2021، وسّع فريق App Engine نطاق دعم العديد من الخدمات المجمّعة ليشمل أوقات التشغيل من الجيل الثاني (كانت متاحة في الأصل فقط في أوقات التشغيل من الجيل الأول)، ما يعني أنّه لم يعُد مطلوبًا منك نقل البيانات من الخدمات المجمّعة، مثل "قائمة مهام App Engine"، إلى الخدمات المكافئة المستقلة من Cloud أو الجهات الخارجية، مثل Cloud Tasks، عند نقل تطبيقك إلى Python 3. بعبارة أخرى، يمكنك مواصلة استخدام Task Queue في تطبيقات Python 3 App Engine طالما أنّك تعدّل الرمز البرمجي للوصول إلى الخدمات المجمّعة من أوقات التشغيل من الجيل التالي.

يمكنك الاطّلاع على مزيد من المعلومات حول كيفية نقل استخدام الخدمات المجمّعة إلى Python 3 في الدرس العملي 17 والفيديو المرتبط به. على الرغم من أنّ هذا الموضوع خارج نطاق الوحدة التدريبية 7، إلا أنّنا أدرجنا أدناه إصدارات Python 3 من كلّ من تطبيقات الوحدة التدريبية 1 و7 التي تم نقلها إلى Python 3 ولا تزال تستخدم App Engine NDB وTask Queue.

8. مراجع إضافية

في ما يلي مراجع إضافية للمطوّرين الذين يريدون استكشاف هذه الوحدة أو وحدة نقل البيانات ذات الصلة بالإضافة إلى المنتجات ذات الصلة. ويشمل ذلك أماكن لتقديم ملاحظات حول هذا المحتوى، وروابط إلى الرمز، ومختلف أجزاء المستندات التي قد تجدها مفيدة.

مشاكل/ملاحظات بشأن الدروس التطبيقية حول الترميز

إذا واجهت أي مشاكل في هذا الدرس العملي، يُرجى البحث عن مشكلتك أولاً قبل إرسالها. روابط للبحث عن مشاكل جديدة وإنشائها:

مراجع لنقل البيانات

يمكنك العثور في الجدول أدناه على روابط لمجلدات المستودع الخاصة بالوحدة 2 (البداية) والوحدة 7 (النهاية).

Codelab

Python 2

Python 3

الوحدة 1

code

الرمز (غير وارد في هذا الدليل التعليمي)

الوحدة 7 (هذا الدرس التطبيقي حول الترميز)

code

الرمز (غير وارد في هذا الدليل التعليمي)

مراجع متوفرة على الإنترنت

في ما يلي مراجع على الإنترنت قد تكون ذات صلة بهذا البرنامج التعليمي:

قائمة انتظار المهام في App Engine

النظام الأساسي لـ App Engine

معلومات أخرى حول السحابة الإلكترونية

الفيديوهات

الترخيص

يخضع هذا العمل لترخيص المشاع الإبداعي مع نسب العمل إلى مؤلفه 2.0 Generic License.