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

1. نظرة عامة

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

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

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

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

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

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

3- الإعداد/التمهيد

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

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

تضمن هذه الخطوات بدء العمل بالتعليمة البرمجية.

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

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

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

أحد المتطلّبات الأساسية لهذا الدرس التطبيقي حول الترميز هو أن يكون لديك تطبيق App Engine صالح للوحدة 1: عليك إكمال الدرس التطبيقي حول الترميز للوحدة 1 (يُنصح به) أو نسخ تطبيق الوحدة 1 من المستودع. سواء كنت تستخدم رمزك أو رمزنا، فإن رمز الوحدة 1 هو المكان الذي سوف "تبدأ" فيه. يرشدك الدرس التطبيقي هذا حول الترميز خلال كل خطوة، وينتهي بتعليمة برمجية تشبه ما هو موجود في مجلد Repo للوحدة 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". قد تحتاج إلى استخدام الأمر pip2 بدلاً من ذلك في حال تثبيت Python 2 وPython 3.
  2. تأكد من تثبيت أداة سطر الأوامر gcloud وإعدادها ومراجعة استخدامها.
  3. عليك إعداد مشروعك على Google 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 إلى إضافة وظيفة "قائمة انتظار المهام". بعض حزم مكتبة بايثون القياسية مطلوبة أيضًا:

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

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

  1. استخراج "أقدم زيارة" الحمولة في الطابع الزمني
  2. تُصدر طلب بحث "مخزن البيانات" للعثور على جميع الكيانات الأقدم من هذا الطابع الزمني.
  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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

موارد نقل البيانات

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

Codelab

Python 2

Python 3

الوحدة 1

الرموز البرمجية

code (الرمز) (غير مدرَج في هذا البرنامج التعليمي)

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

الرموز البرمجية

code (الرمز) (غير مدرَج في هذا البرنامج التعليمي)

مراجع على الإنترنت

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

قائمة مهام App Engine

منصة App Engine

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

الفيديوهات

الترخيص

هذا العمل مرخّص بموجب رخصة المشاع الإبداعي 2.0 مع نسب العمل إلى مؤلف عام.