1. نظرة عامة
تهدف سلسلة البرامج التعليمية حول Serverless Migration Station (برامج تعليمية ذاتية السرعة وعملية) ومقاطع الفيديو ذات الصلة إلى مساعدة مطوّري الحوسبة بدون خادم على Google Cloud في تحديث تطبيقاتهم من خلال إرشادهم خلال عملية نقل واحدة أو أكثر، مع التركيز بشكل أساسي على التخلّي عن الخدمات القديمة. يؤدي ذلك إلى زيادة قابلية نقل تطبيقاتك ويمنحك المزيد من الخيارات والمرونة، ما يتيح لك الدمج مع مجموعة أكبر من منتجات Cloud والوصول إليها، كما يسهّل عليك الترقية إلى أحدث إصدارات اللغة. على الرغم من أنّ هذه السلسلة تركّز في البداية على أوائل مستخدمي Cloud، وخاصةً مطوّري App Engine (البيئة العادية)، إلا أنّها واسعة النطاق بما يكفي لتشمل منصات أخرى بلا خادم، مثل Cloud Functions وCloud Run، أو في أي مكان آخر إذا كان ذلك منطبقًا.
الغرض من هذا الدرس التطبيقي حول الترميز هو توضيح كيفية نقل البيانات من مهام السحب في "قائمة انتظار المهام" في App Engine إلى Cloud Pub/Sub لمطوّري تطبيقات Python 2 في App Engine. هناك أيضًا عملية نقل ضمنية من App Engine NDB إلى Cloud NDB للوصول إلى Datastore (يتم تناولها بشكل أساسي في الوحدة 2)، بالإضافة إلى ترقية إلى الإصدار 3 من Python.
في الوحدة التدريبية 18، ستتعرّف على كيفية إضافة استخدام مهام السحب في تطبيقك. في هذه الوحدة التدريبية، ستأخذ تطبيق الوحدة التدريبية 18 المكتمل وتنقل هذا الاستخدام إلى Cloud Pub/Sub. بالنسبة إلى المستخدمين الذين يستعملون "قوائم انتظار المهام" لتنفيذ مهام الدفع، سيتم نقل بياناتهم إلى Cloud Tasks، وعليهم الرجوع إلى الوحدات 7 إلى 9 بدلاً من ذلك.
ستتعرَّف على كيفية إجراء ما يلي:
- استبدِل استخدام قائمة انتظار المهام في App Engine (مهام السحب) بخدمة Cloud Pub/Sub
- استبدِل استخدام App Engine NDB بـ Cloud NDB (راجِع أيضًا الوحدة 2).
- نقل التطبيق إلى Python 3
المتطلبات
- مشروع Google Cloud Platform مع حساب فوترة نشط على Google Cloud Platform
- مهارات أساسية في لغة Python
- معرفة عملية بالأوامر الشائعة على نظام التشغيل Linux
- معرفة أساسية بشأن تطوير ونشر تطبيقات App Engine
- نموذج تطبيق يعمل على App Engine للوحدة 18
استطلاع
كيف ستستخدم هذا البرنامج التعليمي؟
كيف تقيّم تجربتك مع Python؟
ما هو تقييمك لتجربة استخدام خدمات Google Cloud؟
2. الخلفية
تتيح قائمة انتظار المهام في App Engine مهام الدفع والسحب. لتحسين إمكانية نقل التطبيقات، تنصح Google Cloud بنقل البيانات من الخدمات المجمّعة القديمة، مثل Task Queue، إلى خدمات أخرى مستقلة على Cloud أو خدمات مكافئة تابعة لجهات خارجية.
- على مستخدمي مهام قائمة انتظار المهام التي يتم إرسالها نقل بياناتهم إلى مهام Cloud.
- على مستخدمي مهام قائمة انتظار المهام التي يتمسحبها نقل بياناتهم إلى Cloud Pub/Sub.
تتناول الوحدات 7 إلى 9 عملية نقل المهام التي يتم دفعها، بينما تركّز الوحدات 18 إلى 19 على عملية نقل المهام التي يتم سحبها. في حين أنّ Cloud Tasks تتطابق مع مهام الدفع في Task Queue بشكلٍ أكبر، لا تتطابق Pub/Sub مع مهام السحب في Task Queue بشكلٍ كبير.
تتضمّن Pub/Sub ميزات أكثر من وظيفة السحب التي توفّرها "قائمة المهام". على سبيل المثال، تتضمّن خدمة Pub/Sub أيضًا وظيفة الدفع، ولكنّ خدمة Cloud Tasks تشبه إلى حد كبير مهام الدفع في Task Queue، لذا لا تغطّي أي من وحدات النقل وظيفة الدفع في Pub/Sub. يوضّح هذا الدرس التطبيقي حول الترميز من الوحدة التدريبية 19 كيفية التبديل من قوائم انتظار السحب في "قائمة انتظار المهام" إلى Pub/Sub، بالإضافة إلى نقل البيانات من App Engine NDB إلى Cloud NDB للوصول إلى مخزن البيانات، مع تكرار عملية نقل البيانات في الوحدة التدريبية 2.
على الرغم من أنّ رمز الوحدة 18 "يتم الإعلان عنه" كتطبيق نموذجي متوافق مع Python 2، إلا أنّ المصدر نفسه متوافق مع Python 2 و3، وسيظلّ كذلك حتى بعد الانتقال إلى Cloud Pub/Sub (وCloud NDB) هنا في الوحدة 19.
يتضمّن هذا الدليل التعليمي الخطوات التالية:
- الإعداد/العمل التحضيري
- تعديل الإعدادات
- تعديل الرمز البرمجي للتطبيق
3- الإعداد/العمل التحضيري
يوضّح هذا القسم كيفية تنفيذ ما يلي:
- إعداد مشروعك على السحابة الإلكترونية
- الحصول على نموذج تطبيق أساسي
- (إعادة) نشر تطبيق أساسي وإثبات صحته
- تفعيل خدمات/واجهات برمجة تطبيقات جديدة في Google Cloud
تضمن هذه الخطوات أنّك تبدأ برمز برمجي يعمل وأنّه جاهز للترحيل إلى خدمات السحابة الإلكترونية.
1. إعداد المشروع
إذا أكملت الدرس التطبيقي حول الترميز في الوحدة 18، أعِد استخدام المشروع (والرمز) نفسه. بدلاً من ذلك، يمكنك إنشاء مشروع جديد تمامًا أو إعادة استخدام مشروع حالي آخر. تأكَّد من أنّ المشروع يتضمّن حساب فوترة نشطًا وتطبيق App Engine مفعَّلاً. ابحث عن رقم تعريف مشروعك لأنّك ستحتاج إليه أثناء هذا الدرس التطبيقي حول الترميز، واستخدِمه كلّما صادفت المتغيّر PROJECT_ID.
2. الحصول على نموذج تطبيق أساسي
أحد المتطلبات الأساسية هو توفّر تطبيق يعمل على "الوحدة 18" من App Engine، لذا إما أن تكمل درسًا تطبيقيًا حول الترميز (ننصحك بذلك؛ الرابط أعلاه) أو تنسخ رمز الوحدة 18 من المستودع. سواء استخدمت رمزًا خاصًا بك أو رمزًا من رموزنا، هذه هي الخطوة الأولى ("ابدأ"). يرشدك هذا الدرس التطبيقي حول الترميز خلال عملية نقل البيانات، وينتهي برمز برمجي يشبه الرمز الموجود في مجلد مستودع الوحدة التدريبية 19 ("FINISH").
- START: مجلد الوحدة 18 (Python 2)
- FINISH: مجلد الوحدة 19 (Python 2 و3)
- المستودع بأكمله (لاستنساخ ملف ZIP أو تنزيله)
بغض النظر عن تطبيق الوحدة 18 الذي تستخدمه، من المفترض أن يبدو المجلد كما هو موضّح أدناه، وربما يتضمّن مجلد lib أيضًا:
$ ls README.md appengine_config.py queue.yaml templates app.yaml main.py requirements.txt
3- (إعادة) نشر تطبيق أساسي وإثبات صحته
اتّبِع الخطوات التالية لنشر تطبيق الوحدة التدريبية 18:
- احذف المجلد
libإذا كان هناك مجلد، ثم شغِّلpip install -t lib -r requirements.txtلإعادة ملءlib. قد تحتاج إلى استخدامpip2بدلاً من ذلك إذا كان لديك كل من Python 2 و3 مثبّتَين على جهاز التطوير. - تأكَّد من أنّك ثبَّت وهيّأت أداة سطر الأوامر
gcloudوراجعت طريقة استخدامها. - (اختياري) اضبط مشروعك على السحابة الإلكترونية باستخدام
gcloud config set projectPROJECT_IDإذا كنت لا تريد إدخالPROJECT_IDمع كل أمرgcloudتصدره. - نشر نموذج التطبيق باستخدام
gcloud app deploy - تأكَّد من أنّ التطبيق يعمل على النحو المتوقّع بدون أي مشاكل. إذا أكملت الدرس التطبيقي حول الترميز Module 18، سيعرض التطبيق أهم الزوّار بالإضافة إلى أحدث الزيارات (كما هو موضّح أدناه). إذا لم يكن الأمر كذلك، قد لا تتوفّر أي أعداد للزوّار لعرضها.

قبل ترحيل نموذج تطبيق Module 18، عليك أولاً تفعيل خدمات السحابة الإلكترونية التي سيستخدمها التطبيق المعدَّل.
4. تفعيل خدمات/واجهات برمجة تطبيقات جديدة في Google Cloud
كان التطبيق القديم يستخدم خدمات مجمّعة في App Engine لا تتطلّب إعدادًا إضافيًا، ولكن خدمات Cloud المستقلة تتطلّب ذلك، وسيستخدم التطبيق المعدَّل كلاً من Cloud Pub/Sub وCloud Datastore (من خلال مكتبة برامج Cloud NDB). تتضمّن App Engine وواجهتا Cloud API حصصًا ضمن فئة "دائمًا مجانية"، وطالما أنّك لا تتجاوز هذه الحدود، لن يتم تحصيل رسوم منك مقابل إكمال هذا البرنامج التعليمي. يمكن تفعيل Cloud APIs من Cloud Console أو من سطر الأوامر، حسب ما تفضّله.
من Cloud Console
انتقِل إلى صفحة "مكتبة" في "إدارة واجهات برمجة التطبيقات" (للمشروع الصحيح) في Cloud Console، وابحث عن واجهتَي Cloud Datastore وCloud Pub/Sub API باستخدام شريط البحث في منتصف الصفحة:

انقر على الزر تفعيل لكل واجهة برمجة تطبيقات على حدة، وقد يُطلب منك تقديم معلومات الفوترة. على سبيل المثال، هذه هي صفحة "مكتبة واجهة برمجة التطبيقات" في Cloud Pub/Sub:

من سطر الأوامر
على الرغم من أنّ تفعيل واجهات برمجة التطبيقات من وحدة التحكّم يقدّم معلومات مرئية، يفضّل البعض استخدام سطر الأوامر. أدخِل الأمر gcloud services enable pubsub.googleapis.com datastore.googleapis.com لتفعيل كلتا واجهتَي برمجة التطبيقات في الوقت نفسه:
$ gcloud services enable pubsub.googleapis.com datastore.googleapis.com Operation "operations/acat.p2-aaa-bbb-ccc-ddd-eee-ffffff" finished successfully.
قد يُطلب منك تقديم معلومات الفوترة. إذا أردت تفعيل Cloud APIs أخرى ومعرفة معرّفات الموارد الموحّدة الخاصة بها، يمكنك العثور عليها في أسفل صفحة مكتبة كل واجهة برمجة تطبيقات. على سبيل المثال، لاحظ pubsub.googleapis.com كـ "اسم الخدمة" في أسفل صفحة Pub/Sub أعلاه مباشرةً.
بعد إكمال الخطوات، سيتمكّن مشروعك من الوصول إلى واجهات برمجة التطبيقات. حان الوقت الآن لتعديل التطبيق لاستخدام واجهات برمجة التطبيقات هذه.
4. إنشاء موارد Pub/Sub
في ما يلي ملخّص لترتيب تسلسل سير عمل "قائمة انتظار المهام" من الوحدة التدريبية 18:
- استخدمت الوحدة 18 الملف
queue.yamlلإنشاء قائمة انتظار سحب باسمpullq. - يضيف التطبيق مهامًا إلى قائمة الانتظار لتتبُّع الزوّار.
- ويتم في النهاية معالجة المهام من خلال عامل يتم استئجاره لمدة زمنية محدودة (ساعة واحدة).
- يتم تنفيذ المهام لاحتساب أعداد الزوّار الأخيرة.
- يتم حذف المهام من قائمة الانتظار عند إكمالها.
ستكرّر سير عمل مشابهًا باستخدام Pub/Sub. يعرض القسم التالي مصطلحات Pub/Sub الأساسية، مع ثلاث طرق مختلفة لإنشاء موارد Pub/Sub اللازمة.
مصطلحات App Engine Task Queue (السحب) مقارنةً بمصطلحات Cloud Pub/Sub
يتطلّب التبديل إلى Pub/Sub إجراء تعديل بسيط على المصطلحات التي تستخدمها. في ما يلي الفئات الأساسية مع المصطلحات ذات الصلة من كلا المنتجين. راجِع أيضًا دليل نقل البيانات الذي يتضمّن مقارنات مشابهة.
- بنية بيانات الانتظار في الصف: في "قائمة انتظار المهام"، تنتقل البيانات إلى قوائم انتظار السحب، بينما تنتقل البيانات في Pub/Sub إلى المواضيع.
- وحدات البيانات في قائمة الانتظار: تُعرف مهام السحب في "قائمة انتظار المهام" باسم الرسائل في Pub/Sub.
- معالجات البيانات: باستخدام Task Queue، يمكن للعاملين الوصول إلى مهام السحب، أما باستخدام Pub/Sub، فيجب توفُّر اشتراكات/مشترِكين لتلقّي الرسائل.
- استخراج البيانات: استئجار مهمة سحب هو نفسه سحب رسالة من موضوع (من خلال اشتراك).
- التنظيف/الإكمال: إنّ حذف مهمة من "قائمة انتظار المهام" من قائمة انتظار السحب عند الانتهاء منها يشبه تأكيد رسالة Pub/Sub.
على الرغم من أنّ المنتج الذي يتم وضعه في قائمة الانتظار يتغيّر، يظل سير العمل متشابهًا إلى حدّ ما:
- بدلاً من قائمة انتظار السحب، يستخدم التطبيق موضوعًا باسم
pullq. - بدلاً من إضافة مهام إلى قائمة انتظار سحب، يرسل التطبيق رسائل إلى موضوع (
pullq). - بدلاً من أن يستأجر عامل المهام من قائمة انتظار السحب، يقوم مشترك يُدعى
workerبسحب الرسائل من موضوعpullq. - يعالج التطبيق حمولات الرسائل، ما يؤدي إلى زيادة عدد الزوّار في Datastore.
- بدلاً من حذف المهام من قائمة انتظار السحب، يقرّ التطبيق بالرسائل التي تمت معالجتها.
باستخدام "قائمة انتظار المهام"، يتضمّن الإعداد إنشاء قائمة انتظار السحب. باستخدام Pub/Sub، يتطلّب الإعداد إنشاء موضوع واشتراك. في الوحدة 18، عالجنا queue.yaml خارج تنفيذ التطبيق، والآن يجب تنفيذ الإجراء نفسه باستخدام Pub/Sub.
تتوفّر ثلاثة خيارات لإنشاء المواضيع والاشتراكات:
- من Cloud Console
- من سطر الأوامر
- من الرمز (نص برمجي قصير بلغة Python)
اختَر أحد الخيارات أدناه واتّبِع التعليمات المناسبة لإنشاء موارد Pub/Sub.
من Cloud Console
لإنشاء موضوع من Cloud Console، اتّبِع الخطوات التالية:
- انتقِل إلى صفحة مواضيع النشر/الاشتراك في Cloud Console.
- انقر على إنشاء موضوع في أعلى الصفحة، وسيتم فتح نافذة حوار جديدة (راجِع الصورة أدناه).
- في حقل معرّف الموضوع، أدخِل
pullq. - ألغِ اختيار جميع الخيارات المحدّدة واختَر مفتاح تشفير تُديره Google.
- انقر على زر إنشاء موضوع.
إليك الشكل الذي يظهر به مربّع حوار إنشاء الموضوع:

بعد إنشاء موضوع، يجب إنشاء اشتراك فيه:
- انتقِل إلى صفحة اشتراكات Pub/Sub في Cloud Console.
- انقر على إنشاء اشتراك في أعلى الصفحة (راجِع الصورة أدناه).
- أدخِل
workerفي حقل رقم تعريف الاشتراك. - اختَر
pullqمن القائمة المنسدلة اختيار موضوع Cloud Pub/Sub، مع ملاحظة "اسم المسار المؤهَّل بالكامل"، مثلاًprojects/PROJECT_ID/topics/pullq - بالنسبة إلى نوع التسليم، اختَر Pull.
- اترك جميع الخيارات الأخرى كما هي وانقر على الزر إنشاء.
في ما يلي شكل شاشة إنشاء الاشتراك:

يمكنك أيضًا إنشاء اشتراك من صفحة المواضيع، وقد يكون هذا "الاختصار" مفيدًا لك في المساعدة على ربط المواضيع بالاشتراكات. لمزيد من المعلومات حول إنشاء الاشتراكات، راجِع المستندات.
من سطر الأوامر
يمكن لمستخدمي Pub/Sub إنشاء مواضيع واشتراكات باستخدام الأمرين gcloud pubsub topics create TOPIC_ID وgcloud pubsub subscriptions create SUBSCRIPTION_ID --topic=TOPIC_ID على التوالي. يؤدي تنفيذ هذه العمليات باستخدام TOPIC_ID بقيمة pullq وSUBSCRIPTION_ID بقيمة worker إلى الناتج التالي للمشروع PROJECT_ID:
$ gcloud pubsub topics create pullq Created topic [projects/PROJECT_ID/topics/pullq]. $ gcloud pubsub subscriptions create worker --topic=pullq Created subscription [projects/PROJECT_ID/subscriptions/worker].
يمكنك أيضًا الاطّلاع على هذه الصفحة في مستندات "البدء السريع". قد يؤدي استخدام سطر الأوامر إلى تبسيط مهام سير العمل التي يتم فيها إنشاء المواضيع والاشتراكات بشكل منتظم، ويمكن استخدام هذه الأوامر في نصوص برمجية shell لهذا الغرض.
من الرمز (نص برمجي قصير بلغة Python)
هناك طريقة أخرى لأتمتة إنشاء المواضيع والاشتراكات وهي استخدام واجهة برمجة تطبيقات Pub/Sub في رمز المصدر. في ما يلي الرمز البرمجي للنص maker.py البرمجي في مجلد مستودع الوحدة التدريبية 19.
from __future__ import print_function
import google.auth
from google.api_core import exceptions
from google.cloud import pubsub
_, PROJECT_ID = google.auth.default()
TOPIC = 'pullq'
SBSCR = 'worker'
ppc_client = pubsub.PublisherClient()
psc_client = pubsub.SubscriberClient()
TOP_PATH = ppc_client.topic_path(PROJECT_ID, TOPIC)
SUB_PATH = psc_client.subscription_path(PROJECT_ID, SBSCR)
def make_top():
try:
top = ppc_client.create_topic(name=TOP_PATH)
print('Created topic %r (%s)' % (TOPIC, top.name))
except exceptions.AlreadyExists:
print('Topic %r already exists at %r' % (TOPIC, TOP_PATH))
def make_sub():
try:
sub = psc_client.create_subscription(name=SUB_PATH, topic=TOP_PATH)
print('Subscription created %r (%s)' % (SBSCR, sub.name))
except exceptions.AlreadyExists:
print('Subscription %r already exists at %r' % (SBSCR, SUB_PATH))
try:
psc_client.close()
except AttributeError: # special Py2 handler for grpcio<1.12.0
pass
make_top()
make_sub()
يؤدي تنفيذ هذا النص البرمجي إلى الناتج المتوقّع (في حال عدم حدوث أي أخطاء):
$ python3 maker.py Created topic 'pullq' (projects/PROJECT_ID/topics/pullq) Subscription created 'worker' (projects/PROJECT_ID/subscriptions/worker)
يؤدي استدعاء واجهة برمجة التطبيقات لإنشاء موارد متوفّرة مسبقًا إلى ظهور استثناء google.api_core.exceptions.AlreadyExists في مكتبة البرامج، ويتم التعامل معه بشكل سليم من خلال النص البرمجي:
$ python3 maker.py Topic 'pullq' already exists at 'projects/PROJECT_ID/topics/pullq' Subscription 'worker' already exists at 'projects/PROJECT_ID/subscriptions/worker'
إذا كنت جديدًا على Pub/Sub، يمكنك الاطّلاع على المستند التقني الخاص ببنية Pub/Sub للحصول على مزيد من المعلومات.
5- تعديل الإعدادات
تشمل التعديلات في الإعدادات تغيير ملفات الإعدادات المختلفة بالإضافة إلى إنشاء ما يعادل قوائم انتظار السحب في App Engine ولكن ضمن نظام Cloud Pub/Sub المتكامل.
حذف ملف queue.yaml
سنوقف استخدام Task Queue نهائيًا، لذا احذف queue.yaml لأنّ Pub/Sub لا يستخدم هذا الملف. بدلاً من إنشاء قائمة انتظار سحب، عليك إنشاء موضوعفي Pub/Sub (واشتراك).
requirements.txt
أضِف كلّاً من google-cloud-ndb وgoogle-cloud-pubsub إلى requirements.txt للانضمام إلى flask من الوحدة 18. يجب أن تبدو الوحدة 19 requirements.txt المعدَّلة الآن على النحو التالي:
flask
google-cloud-ndb
google-cloud-pubsub
لا يحتوي ملف requirements.txt هذا على أي أرقام إصدارات، ما يعني أنّه تم اختيار أحدث الإصدارات. في حال حدوث أي حالات عدم توافق، اتّبِع الممارسة العادية لاستخدام أرقام الإصدارات لتحديد الإصدارات المتوافقة مع التطبيق.
app.yaml
تختلف التغييرات في app.yaml حسب ما إذا كنت ستواصل استخدام Python 2 أو ستتم الترقية إلى Python 3.
Python 2
يضيف التعديل أعلاه على requirements.txt استخدام مكتبات برامج Google Cloud. تتطلّب هذه الميزات دعمًا إضافيًا من App Engine، وتحديدًا بعض المكتبات المضمّنة، setuptools وgrpcio. يتطلّب استخدام المكتبات المضمّنة توفُّر القسم libraries في app.yaml وأرقام إصدارات المكتبات، أو "الأحدث" للإشارة إلى أحدث إصدار متاح على خوادم App Engine. لا تتضمّن الوحدة 18 app.yaml أحد الأقسام التالية بعد:
قبل:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
أضِف قسم libraries إلى app.yaml مع إدخالات لكل من setuptools وgrpcio، واختَر أحدث إصداراتهما. أضِف أيضًا إدخالًا runtime بديلًا لـ Python 3، مع إيقاف التعليق عليه مع إصدار 3.x حالي، مثل 3.10، في وقت كتابة هذا المستند. بعد إجراء هذه التغييرات، سيظهر app.yaml على النحو التالي:
بعد:
#runtime: python310
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
libraries:
- name: setuptools
version: latest
- name: grpcio
version: latest
Python 3
بالنسبة إلى مستخدمي Python 3 وapp.yaml، فإنّ الأمر يتعلق بإزالة العناصر. في هذا القسم، عليك حذف القسم handlers والتوجيهَين threadsafe وapi_version، ولن تنشئ القسم libraries.
لا توفّر بيئات التشغيل من الجيل الثاني مكتبات مضمّنة تابعة لجهات خارجية، لذا لا يلزم توفير القسم libraries في app.yaml. بالإضافة إلى ذلك، لم يعُد من الضروري نسخ (يُعرف أحيانًا باسم التوريد أو التجميع الذاتي) حِزم تابعة لجهات خارجية غير مضمّنة. ما عليك سوى إدراج مكتبات الجهات الخارجية التي يستخدمها تطبيقك في requirements.txt.
يُستخدَم القسم handlers في app.yaml لتحديد معالجات التطبيقات (البرامج النصية) والملفات الثابتة. بما أنّ وقت تشغيل Python 3 يتطلّب أن تنفّذ أُطر عمل الويب عملية التوجيه الخاصة بها، يجب تغيير جميع معالجات النصوص البرمجية إلى auto. إذا كان تطبيقك (مثل تطبيق الوحدة 18) لا يعرض ملفات ثابتة، ستكون جميع المسارات auto، ما يجعلها غير ذات صلة. نتيجةً لذلك، لن تحتاج إلى القسم handlers أيضًا، لذا احذفه.
أخيرًا، لا يتم استخدام التوجيهَين threadsafe وapi_version في Python 3، لذا احذفهما أيضًا. الخلاصة هي أنّه عليك حذف جميع أقسام app.yaml ليبقى التوجيه runtime فقط، مع تحديد إصدار حديث من Python 3، مثل 3.10. في ما يلي الشكل الذي يظهر به app.yaml قبل هذه التعديلات وبعدها:
قبل:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
بعد:
runtime: python310
بالنسبة إلى المستخدمين الذين لم يستعدوا بعد لحذف كل شيء من app.yaml في Python 3، وفّرنا ملف app3.yaml بديل في مجلد مستودع الوحدة 19. إذا كنت تريد استخدام هذا الملف بدلاً من الملف الآخر في عمليات النشر، احرص على إلحاق اسم الملف هذا بنهاية الأمر: gcloud app deploy app3.yaml (وإلا سيتم تلقائيًا استخدام ملف Python 2 app.yaml الذي لم تغيّره ونشر تطبيقك به).
appengine_config.py
إذا كنت بصدد الترقية إلى Python 3، لن تحتاج إلى appengine_config.py، لذا احذفه. والسبب في عدم الحاجة إلى ذلك هو أنّ إتاحة استخدام مكتبات تابعة لجهات خارجية تتطلّب فقط تحديدها في requirements.txt. إذا كنت تستخدم الإصدار 2 من Python، يُرجى مواصلة القراءة.
يحتوي الإصدار appengine_config.py من الوحدة 18 على الرمز المناسب لتوفير الدعم لمكتبات الجهات الخارجية، مثل Flask ومكتبات برامج Cloud التي تمت إضافتها للتو إلى requirements.txt:
قبل:
from google.appengine.ext import vendor
# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)
ومع ذلك، لا يكفي هذا الرمز وحده لدعم المكتبات المضمّنة التي تمت إضافتها للتو (setuptools وgrpcio)، بل يجب إضافة بضعة أسطر أخرى، لذا عدِّل appengine_config.py ليصبح على النحو التالي:
بعد:
import pkg_resources
from google.appengine.ext import vendor
# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)
# Add libraries to pkg_resources working set to find the distribution.
pkg_resources.working_set.add_entry(PATH)
يمكنك الاطّلاع على مزيد من التفاصيل حول التغييرات المطلوبة لتوافق مكتبات برامج Cloud مع مستندات نقل الخدمات المجمّعة.
تعديلات أخرى على الإعدادات
إذا كان لديك مجلد lib، احذفه. إذا كنت تستخدم الإصدار 2 من Python، عليك إعادة ملء المجلد lib بإدخال الأمر التالي:
pip install -t lib -r requirements.txt # or pip2
إذا كان لديك الإصداران 2 و3 من Python مثبّتَين على نظام التطوير، قد تحتاج إلى استخدام pip2 بدلاً من pip.
6. تعديل الرمز البرمجي للتطبيق
يتضمّن هذا القسم تحديثات لملف التطبيق الرئيسي، main.py، ما يؤدي إلى استبدال استخدام قوائم انتظار السحب في "قائمة مهام App Engine" بخدمة Cloud Pub/Sub. لم يتم إجراء أي تغييرات على نموذج الويب templates/index.html. يجب أن يعمل كلا التطبيقين بشكل مماثل، وأن يعرضا البيانات نفسها.
تعديل عمليات الاستيراد والإعداد
هناك عدّة تعديلات على عمليات الاستيراد والتهيئة:
- بالنسبة إلى عمليات الاستيراد، استبدِل App Engine NDB وTask Queue بـ Cloud NDB وPub/Sub.
- أعِد تسمية
pullqمن اسمQUEUEإلى اسمTOPIC. - في السابق، كان العامل يستأجر المهام لمدة ساعة، ولكن مع Pub/Sub، يتم قياس المهلات على أساس كل رسالة، لذا احذف الثابت
HOUR. - تتطلّب Cloud APIs استخدام برنامج عميل لواجهة برمجة التطبيقات، لذا ابدأ في إعدادها لكلّ من Cloud NDB وCloud Pub/Sub، مع توفير الأخير لبرامج العملاء لكلّ من المواضيع والاشتراكات.
- يتطلّب Pub/Sub رقم تعريف مشروع على السحابة الإلكترونية، لذا عليك استيراده والحصول عليه من
google.auth.default(). - تتطلّب خدمة "Pub/Sub" "أسماء مسارات مؤهَّلة بالكامل" للمواضيع والاشتراكات، لذا أنشئها باستخدام دوال
*_path()المريحة.
في ما يلي عمليات الاستيراد والتهيئة من الوحدة 18، بالإضافة إلى الشكل الذي يجب أن تبدو عليه الأقسام بعد تنفيذ التغييرات أعلاه، مع العلم أنّ معظم الرموز الجديدة هي موارد مختلفة من Pub/Sub:
قبل:
from flask import Flask, render_template, request
from google.appengine.api import taskqueue
from google.appengine.ext import ndb
HOUR = 3600
LIMIT = 10
TASKS = 1000
QNAME = 'pullq'
QUEUE = taskqueue.Queue(QNAME)
app = Flask(__name__)
بعد:
from flask import Flask, render_template, request
import google.auth
from google.cloud import ndb, pubsub
LIMIT = 10
TASKS = 1000
TOPIC = 'pullq'
SBSCR = 'worker'
app = Flask(__name__)
ds_client = ndb.Client()
ppc_client = pubsub.PublisherClient()
psc_client = pubsub.SubscriberClient()
_, PROJECT_ID = google.auth.default()
TOP_PATH = ppc_client.topic_path(PROJECT_ID, TOPIC)
SUB_PATH = psc_client.subscription_path(PROJECT_ID, SBSCR)
تعديلات على نموذج بيانات الزيارات
لا يتغيّر نموذج بيانات Visit. يتطلّب الوصول إلى Datastore استخدامًا صريحًا لأداة إدارة سياق عميل Cloud NDB API، ds_client.context(). في الرمز البرمجي، يعني ذلك أنّه عليك تضمين طلبات Datastore في كل من store_visit() وfetch_visits() داخل كتل with في Python. هذا التحديث مطابق لما تم تناوله في الوحدة 2.
التغيير الأكثر صلة بخدمة Pub/Sub هو استبدال عملية وضع مهمة سحب في "قائمة المهام" بعملية نشر رسالة Pub/Sub إلى الموضوع pullq. في ما يلي الرمز البرمجي قبل إجراء هذه التعديلات وبعدها:
قبل:
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 in Datastore and queue request to bump visitor count'
Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
QUEUE.add(taskqueue.Task(payload=remote_addr, method='PULL'))
def fetch_visits(limit):
'get most recent visits'
return Visit.query().order(-Visit.timestamp).fetch(limit)
بعد:
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 in Datastore and queue request to bump visitor count'
with ds_client.context():
Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
ppc_client.publish(TOP_PATH, remote_addr.encode('utf-8'))
def fetch_visits(limit):
'get most recent visits'
with ds_client.context():
return Visit.query().order(-Visit.timestamp).fetch(limit)
تعديلات على نموذج بيانات VisitorCount
لا يتغيّر نموذج بيانات VisitorCount ولا ينفّذ fetch_counts() باستثناء تضمين طلب بحث Datastore داخل كتلة with، كما هو موضّح أدناه:
قبل:
class VisitorCount(ndb.Model):
visitor = ndb.StringProperty(repeated=False, required=True)
counter = ndb.IntegerProperty()
def fetch_counts(limit):
'get top visitors'
return VisitorCount.query().order(-VisitorCount.counter).fetch(limit)
بعد:
class VisitorCount(ndb.Model):
visitor = ndb.StringProperty(repeated=False, required=True)
counter = ndb.IntegerProperty()
def fetch_counts(limit):
'get top visitors'
with ds_client.context():
return VisitorCount.query().order(-VisitorCount.counter).fetch(limit)
تعديل رمز العامل
يتم تعديل رمز العامل من خلال استبدال NDB بـ Cloud NDB وTask Queue بـ Pub/Sub، ولكن يبقى سير العمل كما هو.
- ضَع طلبات Datastore في كتلة مدير سياق Cloud NDB
with. - تتضمّن عملية تنظيف "قائمة انتظار المهام" حذف جميع المهام من قائمة انتظار السحب. باستخدام Pub/Sub، يتم جمع "معرّفات الإقرار" في
acksثم يتم حذفها أو الإقرار بها في النهاية. - يتم استئجار مهام السحب في "قائمة انتظار المهام" بطريقة مشابهة لطريقة سحب رسائل Pub/Sub. في حين يتم حذف مهام السحب باستخدام عناصر المهام نفسها، يتم حذف رسائل Pub/Sub من خلال أرقام التعريف الخاصة بإقرار الاستلام.
- تتطلّب حمولات رسائل Pub/Sub وحدات بايت (وليس سلاسل Python)، لذا يتم ترميز UTF-8 وفك ترميزه عند نشر الرسائل في موضوع وسحبها منه على التوالي.
استبدِل log_visitors() بالرمز المعدَّل أدناه الذي يتضمّن التغييرات الموضّحة للتو:
قبل:
@app.route('/log')
def log_visitors():
'worker processes recent visitor counts and updates them in Datastore'
# tally recent visitor counts from queue then delete those tasks
tallies = {}
tasks = QUEUE.lease_tasks(HOUR, TASKS)
for task in tasks:
visitor = task.payload
tallies[visitor] = tallies.get(visitor, 0) + 1
if tasks:
QUEUE.delete_tasks(tasks)
# increment those counts in Datastore and return
for visitor in tallies:
counter = VisitorCount.query(VisitorCount.visitor == visitor).get()
if not counter:
counter = VisitorCount(visitor=visitor, counter=0)
counter.put()
counter.counter += tallies[visitor]
counter.put()
return 'DONE (with %d task[s] logging %d visitor[s])\r\n' % (
len(tasks), len(tallies))
بعد:
@app.route('/log')
def log_visitors():
'worker processes recent visitor counts and updates them in Datastore'
# tally recent visitor counts from queue then delete those tasks
tallies = {}
acks = set()
rsp = psc_client.pull(subscription=SUB_PATH, max_messages=TASKS)
msgs = rsp.received_messages
for rcvd_msg in msgs:
acks.add(rcvd_msg.ack_id)
visitor = rcvd_msg.message.data.decode('utf-8')
tallies[visitor] = tallies.get(visitor, 0) + 1
if acks:
psc_client.acknowledge(subscription=SUB_PATH, ack_ids=acks)
try:
psc_client.close()
except AttributeError: # special handler for grpcio<1.12.0
pass
# increment those counts in Datastore and return
if tallies:
with ds_client.context():
for visitor in tallies:
counter = VisitorCount.query(VisitorCount.visitor == visitor).get()
if not counter:
counter = VisitorCount(visitor=visitor, counter=0)
counter.put()
counter.counter += tallies[visitor]
counter.put()
return 'DONE (with %d task[s] logging %d visitor[s])\r\n' % (
len(msgs), len(tallies))
لم يتم إجراء أي تغييرات على معالج التطبيق الرئيسي root(). لا يلزم إجراء أي تغييرات في ملف نموذج HTML، templates/index.html، وبالتالي يشتمل ذلك على جميع التعديلات اللازمة. تهانينا على وصولك إلى تطبيق الوحدة 19 الجديد باستخدام Cloud Pub/Sub.
7. الملخّص/التنظيف
عليك نشر تطبيقك للتأكّد من أنّه يعمل على النحو المنشود وفي أي ناتج معروض. شغِّل أيضًا العامل لمعالجة عدد الزوّار. بعد التحقّق من التطبيق، اتّخِذ أي خطوات تنظيف وفكِّر في الخطوات التالية.
نشر التطبيق والتحقّق منه
تأكَّد من أنّك أنشأت موضوع pullq واشتراك worker. إذا تم إكمال ذلك وأصبح نموذج تطبيقك جاهزًا، يمكنك نشر تطبيقك باستخدام gcloud app deploy. يجب أن تكون المخرجات مماثلة لتلك التي ينتجها تطبيق الوحدة 18، باستثناء أنّك استبدلت آلية وضع المهام في قائمة الانتظار الأساسية بالكامل بنجاح:

تتحقّق واجهة المستخدم الأمامية على الويب للتطبيق الآن من أنّ هذا الجزء من التطبيق يعمل. على الرغم من أنّ هذا الجزء من التطبيق يطلب بنجاح عرض أهم الزوّار وأحدث الزيارات، تذكَّر أنّ التطبيق يسجّل هذه الزيارة بالإضافة إلى إنشاء مهمة سحب لإضافة هذا الزائر إلى العدد الإجمالي. تمت إضافة هذه المهمة الآن إلى قائمة الانتظار في انتظار معالجتها.
يمكنك تنفيذ ذلك باستخدام خدمة خلفية في App Engine أو مهمة cron أو الانتقال إلى /log أو إصدار طلب HTTP من سطر الأوامر. في ما يلي مثال على تنفيذ الرمز البرمجي للعامل باستخدام curl (استبدِل PROJECT_ID):
$ curl https://PROJECT_ID.appspot.com/log DONE (with 1 task[s] logging 1 visitor[s])
سيظهر العدد المعدَّل عند زيارة الموقع الإلكتروني في المرة التالية. هذا كل شيء!
تَنظيم
للجمهور العام
إذا انتهيت من استخدام التطبيق في الوقت الحالي، ننصحك بإيقاف تطبيق 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/imagesconsole.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com- تعتمد روابط مساحة التخزين أعلاه على
PROJECT_IDو *LOC*، على سبيل المثال، "us" إذا كان تطبيقك مستضافًا في الولايات المتحدة.
من ناحية أخرى، إذا كنت لن تواصل استخدام هذا التطبيق أو غيره من الدروس التعليمية البرمجية المتعلقة بنقل البيانات وأردت حذف كل شيء تمامًا، عليك إيقاف مشروعك.
خاص بهذا الدرس التطبيقي حول الترميز
الخدمات المدرَجة أدناه خاصة بهذا الدرس التطبيقي حول الترميز. يُرجى الرجوع إلى مستندات كل منتج للحصول على مزيد من المعلومات:
- تتضمّن المكوّنات المختلفة في Cloud Pub/Sub فئة مجانية، لذا حدِّد استخدامك الإجمالي للحصول على فكرة أفضل عن الآثار المترتبة على التكلفة، واطّلِع على صفحة الأسعار للحصول على مزيد من التفاصيل.
- يتم توفير خدمة App Engine Datastore من خلال Cloud Datastore (Cloud Firestore في وضع Datastore) الذي يتضمّن أيضًا طبقة مجانية. يمكنك الاطّلاع على صفحة الأسعار للحصول على مزيد من المعلومات.
الخطوات التالية
بالإضافة إلى هذا البرنامج التعليمي، تتضمّن وحدات نقل البيانات الأخرى التي تركّز على التوقّف عن استخدام الخدمات المجمّعة القديمة ما يلي:
- الوحدة 2: نقل البيانات من App Engine
ndbإلى Cloud NDB - الوحدات من 7 إلى 9: نقل البيانات من App Engine Task Queue (مهام الدفع) إلى Cloud Tasks
- الوحدتان 12 و13: نقل البيانات من App Engine Memcache إلى Cloud Memorystore
- الوحدتان 15 و16: نقل البيانات من App Engine Blobstore إلى Cloud Storage
لم تعُد App Engine هي المنصة الوحيدة بدون خادم في Google Cloud. إذا كان لديك تطبيق صغير على App Engine أو تطبيق بوظائف محدودة وتريد تحويله إلى خدمة مصغّرة مستقلة، أو إذا كنت تريد تقسيم تطبيق متكامل إلى عدة مكونات قابلة لإعادة الاستخدام، ستكون هذه أسبابًا وجيهة للنقل إلى Cloud Functions. إذا أصبحت عملية إنشاء الحاويات جزءًا من سير عمل تطوير التطبيقات، خاصةً إذا كانت تتألف من مسار CI/CD (التكامل المستمر/التسليم المتواصل أو النشر المستمر)، ننصحك بالانتقال إلى Cloud Run. تتناول الوحدات التدريبية التالية هذه السيناريوهات:
- نقل البيانات من App Engine إلى Cloud Functions: يمكنك الاطّلاع على الوحدة 11
- الانتقال من App Engine إلى Cloud Run: يمكنك الاطّلاع على الوحدة 4 لتضمين تطبيقك في حاوية باستخدام Docker، أو الوحدة 5 لإجراء ذلك بدون حاويات أو معرفة بـ Docker أو
Dockerfile
إنّ الانتقال إلى منصة أخرى بلا خادم هو أمر اختياري، وننصحك بمراجعة أفضل الخيارات لتطبيقاتك وحالات الاستخدام قبل إجراء أي تغييرات.
بغض النظر عن وحدة النقل التي ستختارها، يمكنك الوصول إلى كل محتوى Serverless Migration Station (الدروس البرمجية والفيديوهات ورمز المصدر [عند توفّره]) من خلال مستودع المصدر المفتوح. يوفّر مستودع README أيضًا إرشادات حول عمليات نقل البيانات التي يجب أخذها في الاعتبار وأي "ترتيب" ذي صلة لوحدات نقل البيانات.
8. مراجع إضافية
في ما يلي مراجع إضافية للمطوّرين الذين يريدون استكشاف هذه الوحدة أو وحدة نقل البيانات ذات الصلة بالإضافة إلى المنتجات ذات الصلة. ويشمل ذلك أماكن لتقديم ملاحظات حول هذا المحتوى، وروابط إلى الرمز، ومختلف أجزاء المستندات التي قد تجدها مفيدة.
مشاكل/ملاحظات بشأن الدروس التطبيقية حول الترميز
إذا واجهت أي مشاكل في هذا الدرس العملي، يُرجى البحث عن مشكلتك أولاً قبل إرسالها. روابط للبحث عن مشاكل جديدة وإنشائها:
مراجع لنقل البيانات
يمكنك العثور على روابط لمجلدات المستودع لكل من الوحدة التدريبية 18 (البداية) والوحدة التدريبية 19 (النهاية) في الجدول أدناه.
Codelab | Python 2 | Python 3 |
(غير متوفر) | ||
الوحدة 19 (هذا الدرس التطبيقي حول الترميز) | (كما هو الحال في Python 2، باستثناء استخدام app3.yaml ما لم يتم تعديل app.yaml كما هو موضح أعلاه) |
المراجع على الإنترنت
في ما يلي مراجع ذات صلة بهذا البرنامج التعليمي:
قائمة انتظار المهام في App Engine
- نظرة عامة على "قائمة مهام App Engine"
- نظرة عامة على قوائم انتظار السحب في "قائمة انتظار المهام" في App Engine
- نموذج تطبيق كامل لقائمة انتظار السحب في "قائمة انتظار المهام" App Engine
- إنشاء قوائم انتظار سحب في Task Queue
- فيديو إطلاق قائمة انتظار السحب في مؤتمر Google I/O لعام 2011 ( نموذج تطبيق Votelator)
queue.yamlمرجعqueue.yamlمقابل Cloud Tasks- دليل نقل بيانات قوائم الانتظار إلى Pub/Sub
خدمة Cloud Pub/Sub
- صفحة منتج Cloud Pub/Sub
- استخدام مكتبات برامج Pub/Sub
- عيّنات مكتبة برامج Python في Pub/Sub
- مستندات مكتبة برامج Pub/Sub Python
- إنشاء مواضيع Pub/Sub وإدارتها
- إرشادات اختيار أسماء مواضيع Pub/Sub
- إنشاء اشتراكات Pub/Sub وإدارتها
- تطبيق نموذجي لبيئة App Engine المرنة (يمكن نشره في البيئة العادية أيضًا، باستخدام Python 3)
- مستودع التطبيق النموذجي أعلاه
- اشتراكات السحب في Pub/Sub
- اشتراكات Pub/Sub التي يعرضها الناشر
- نموذج تطبيق App Engine Pub/Sub لإرسال الرسائل (Python 3)
- مستودع تطبيق نموذجي لإرسال Pub/Sub في App Engine
- معلومات عن أسعار Pub/Sub
- Cloud Tasks أو Cloud Pub/Sub؟ (الدفع مقابل السحب)
App Engine NDB وCloud NDB (تخزين البيانات)
- مستندات NDB في App Engine
- مستودع App Engine NDB
- مستندات Google Cloud NDB
- مستودع Google Cloud NDB
- معلومات أسعار Cloud Datastore
النظام الأساسي لـ App Engine
- مستندات App Engine
- وقت تشغيل Python 2 App Engine (البيئة العادية)
- استخدام المكتبات المضمّنة في App Engine على Python 2 App Engine
- وقت تشغيل Python 3 App Engine (البيئة العادية)
- الاختلافات بين أوقات تشغيل Python 2 و3 في App Engine (البيئة العادية)
- دليل نقل البيانات من Python 2 إلى Python 3 في App Engine (البيئة العادية)
- معلومات الأسعار والحصص في App Engine
- إطلاق الجيل الثاني من منصة App Engine (2018)
- مقارنة بين الجيل الأول والثاني من المنصات
- الدعم الطويل الأمد لأوقات التشغيل القديمة
- أمثلة على نقل المستندات
- عينات نقل البيانات التي يقدّمها المنتدى
معلومات أخرى حول السحابة الإلكترونية
- Python على Google Cloud Platform
- مكتبات برامج Python في Google Cloud
- فئة "دائمًا مجانية" في Google Cloud
- Google Cloud SDK (أداة سطر الأوامر
gcloud) - جميع مستندات Google Cloud
الفيديوهات
- Serverless Migration Station
- أداة "استكشافات" بدون خادم
- الاشتراك في قناة Google Cloud Tech
- الاشتراك في Google Developers
الترخيص
يخضع هذا العمل لترخيص المشاع الإبداعي مع نسب العمل إلى مؤلفه 2.0 Generic License.