نقل البيانات من قائمة انتظار مهام App Engine إلى السحب إلى Cloud Pub/Sub (الوحدة 19)

1. نظرة عامة

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

الغرض من هذا الدرس التطبيقي حول الترميز هو شرح لمطوّري تطبيقات Python 2 App Engine كيفية نقل المهام من قائمة انتظار مهام App Engine إلى Cloud Pub/Sub. هناك أيضًا نقل ضمني من App Engine NDB إلى Cloud NDB للوصول إلى مخزن البيانات (الذي تشمله الوحدة 2 بشكل أساسي) بالإضافة إلى الترقية إلى Python 3.

في الوحدة 18، ستتعرف على كيفية استخدام مهام سحب في تطبيقك. في هذه الوحدة، عليك استخدام تطبيق الوحدة 18 المكتمل ونقل هذا الاستخدام إلى خدمة Cloud Pub/Sub. وبدلاً من ذلك، سيتم نقل المستخدمين الذين يستخدمون قوائم انتظار المهام لتنفيذ مهام الدفع إلى "مهام Cloud" وعليك الرجوع إلى الوحدات من 7 إلى 9 بدلاً من ذلك.

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

المتطلبات

استطلاع

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

قراءة النص فقط اقرأها وأكمِل التمارين

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

حديث متوسط بارع

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

حديث متوسط بارع

2. الخلفية

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

تغطي وحدات النقل 7-9 نقل مهام الدفع، بينما تركز الوحدات 18-19 على نقل مهمة السحب. بينما تتطابق مهام Cloud مع مهام دفع قائمة انتظار المهام بشكل أوثق، فإن Pub/Sub ليست قريبة من مهام السحب التناظرية لقائمة انتظار المهام.

يحتوي نشر/الاشتراك على ميزات أكثر من وظيفة السحب التي توفرها قائمة انتظار المهام. على سبيل المثال، تشتمل خدمة Pub/Sub أيضًا على وظيفة الدفع، إلا أنّ خدمة Cloud Tasks تشبه مهام الإرسال في قائمة انتظار المهام، لذلك لا تشمل أي من وحدات نقل البيانات إرسال النشر/الاشتراك. يوضح الدرس التطبيقي حول ترميز الوحدة 19 هذا تبديل آلية وضع الانتظار في قائمة انتظار المهام إلى Pub/Sub بالإضافة إلى الانتقال من App Engine NDB إلى Cloud NDB للوصول إلى "مخزن البيانات"، وتكرار نقل الوحدة 2.

في حين أن رمز الوحدة 18 "مُعلَن عنه" باعتباره نموذجًا لتطبيق Python 2، يكون المصدر نفسه متوافقًا مع Python 2 وPython، ويبقى على هذا النحو حتى بعد النقل إلى Cloud Pub/Sub (وCloud NDB) هنا في الوحدة 19.

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

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

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

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

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

تضمن هذه الخطوات بدء استخدام رمز صالح ومن استعداده لنقل البيانات إلى خدمات السحابة الإلكترونية.

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

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

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

ويتمثّل أحد المتطلّبات الأساسية في تطبيق Module 18 App Engine قيد التشغيل، لذلك عليك إما إكمال الدرس التطبيقي حول الترميز (الإجراء المقترَح، الرابط أعلاه) أو نسخ رمز الوحدة 18 من المستودع. وسواء كنت تستخدم نظامك أو استخدامك، هذا هو المكان الذي سنبدأ فيه ("البدء"). يرشدك هذا الدرس التطبيقي حول الترميز خلال عملية النقل، وختامًا باستخدام رمز يشبه ما هو في مجلد Repo للوحدة 19 ("FINISH").

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

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

3- (إعادة) نشر التطبيق الأساسي والتحقّق من صحته

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

  1. احذف المجلد "lib" في حال توفّره وشغِّل pip install -t lib -r requirements.txt لإعادة تعبئة "lib". قد تحتاج إلى استخدام pip2 بدلاً من ذلك في حال تثبيت Python 2 و3 على جهاز التطوير.
  2. تأكَّد من تثبيت أداة سطر الأوامر gcloud وإعدادها ومراجعة استخدامها.
  3. (اختياري) يمكنك ضبط مشروعك على Google Cloud باستخدام gcloud config set project PROJECT_ID في حال كنت لا تريد إدخال PROJECT_ID مع كل أمر gcloud تصدره.
  4. نشر نموذج التطبيق باستخدام "gcloud app deploy"
  5. تأكَّد من أنّ التطبيق يعمل على النحو المتوقّع بدون أي مشكلة. إذا أكملت الدرس التطبيقي حول الترميز الخاص بالوحدة 18، سيعرض التطبيق أهم الزوّار مع أحدث الزيارات (الموضّحة أدناه). وإذا لم يكن الأمر كذلك، قد لا يكون هناك أي أعداد زوّار لعرضها.

b667551dcbab1a09.png

قبل نقل نموذج الوحدة 18، يجب أولاً تفعيل خدمات السحابة الإلكترونية التي سيستخدمها التطبيق المُعدَّل.

4. تفعيل خدمات Google Cloud/واجهات برمجة التطبيقات الجديدة

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

من Cloud Console

انتقِل إلى صفحة "مكتبة مدير واجهة برمجة التطبيقات" (للمشروع الصحيح) في Cloud Console، وابحث عن "مخزن البيانات في السحابة الإلكترونية" وواجهات برمجة تطبيقات Cloud Pub/Sub باستخدام شريط البحث في منتصف الصفحة:

c7a740304e9d35b.png

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

1b6c0a2a73124f6b.jpeg

من سطر الأوامر

وعلى الرغم من كونها غنية بالمعلومات المرئية لتمكين واجهات برمجة التطبيقات من وحدة التحكم، يفضل البعض سطر الأوامر. أصدر الأمر 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 أخرى وتريد معرفة معرّفات الموارد المنتظمة (URI) الخاصة بها، يمكنك العثور عليها أسفل صفحة مكتبة كل واجهة برمجة تطبيقات. على سبيل المثال، يجب الانتباه إلى pubsub.googleapis.com باعتباره "اسم الخدمة" في أسفل صفحة النشر/الاشتراك أعلاه.

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

4. إنشاء مراجع النشر/الاشتراك

ملخص ترتيب تسلسل سير عمل قائمة انتظار المهام من الوحدة 18:

  1. استخدمت الوحدة 18 ملف queue.yaml لإنشاء قائمة انتظار سحب باسم pullq.
  2. يضيف التطبيق مهام إلى قائمة انتظار السحب لتتبع الزائرين.
  3. يعالج العامل في النهاية المهام، ويتم تأجيرها لفترة زمنية محدودة (ساعة).
  4. يتم تنفيذ المهام لحساب أعداد الزوّار الأخيرة.
  5. يتم حذف المهام من قائمة الانتظار عند اكتمالها.

أنت بصدد تكرار سير عمل مماثل مع النشر/الاشتراك. يتناول القسم التالي مصطلحات النشر/الاشتراك الأساسية، مع ثلاث طرق مختلفة لإنشاء موارد النشر/الاشتراك اللازمة.

قائمة انتظار مهام App Engine (سحب) مقابل مصطلحات Cloud Pub/Sub

وتتطلب هذه الميزة تعديلاً طفيفًا في مفردات اللغة. في ما يلي الفئات الأساسية مع العبارات ذات الصلة من كلا المنتجَين. يُرجى أيضًا مراجعة دليل نقل البيانات الذي يحتوي على مقارنات مشابهة.

  • بنية البيانات في "قائمة المحتوى التالي": باستخدام قائمة انتظار المهام، يتم نقل البيانات إلى قوائم الانتظار القابلة للسحب. باستخدام ميزة "النشر/الاشتراك"، تدخل البيانات في المواضيع.
  • وحدات البيانات في قائمة الانتظار: تُسمى مهام السحب التي تضم قائمة انتظار المهام الرسائل التي تحتوي على نشر/اشتراك.
  • معالِجات البيانات: باستخدام قائمة المهام، يمكن للعاملين الوصول إلى مهام السحب. باستخدام ميزة "النشر/الاشتراك"، ستحتاج إلى اشتراكات/مشتركين لتلقّي الرسائل
  • استخراج البيانات: استئجار مهمة سحب هي نفسها عملية سحب رسالة من موضوع (من خلال اشتراك).
  • تنظيف/الإكمال: يشبه حذف مهمة قائمة انتظار المهام من قائمة انتظار السحب عند الانتهاء الإقرار برسالة Pub/Sub.

على الرغم من تغيُّر المنتجات في "قائمة المحتوى التالي"، يبقى سير العمل متشابهًا نسبيًا:

  1. بدلاً من استخدام قائمة انتظار السحب، يستخدم التطبيق موضوعًا باسم pullq.
  2. بدلاً من إضافة مهام إلى قائمة انتظار السحب، يرسل التطبيق رسائل إلى موضوع (pullq).
  3. بدلاً من أن يستأجر موظف يستأجر مهامًا من قائمة انتظار السحب، يسحب المشترك المسمى worker الرسائل من الموضوع pullq.
  4. يعالج التطبيق حمولات الرسائل، ما يزيد من عدد الزوّار في "مخزن البيانات".
  5. بدلاً من حذف المهام من قائمة انتظار السحب، يبلغ التطبيق الرسائل التي تمت معالجتها.

باستخدام قائمة انتظار المهام، يتضمن الإعداد إنشاء قائمة انتظار السحب. باستخدام نشر/اشتراك، يتطلب الإعداد إنشاء موضوع واشتراك. في الوحدة 18، عالجنا queue.yaml خارج نطاق تنفيذ التطبيق. يجب الآن تنفيذ الأمر نفسه مع النشر/الاشتراك.

هناك ثلاثة خيارات لإنشاء المواضيع والاشتراكات:

  1. من Cloud Console
  2. من سطر الأوامر أو
  3. من الرمز (نص برمجي قصير بلغة Python)

حدِّد أحد الخيارات أدناه واتّبِع التعليمات المناسبة لإنشاء موارد النشر/الاشتراك.

من Cloud Console

لإنشاء موضوع من Cloud Console، اتّبِع الخطوات التالية:

  1. انتقِل إلى صفحة "مواضيع النشر/الاشتراك" في Cloud Console.
  2. انقر على إنشاء موضوع في أعلى الصفحة، يتم فتح نافذة مربّع حوار جديدة (انظر الصورة أدناه)
  3. في حقل رقم تعريف الموضوع، أدخِل pullq.
  4. ألغِ تحديد جميع الخيارات التي تم وضع علامة عليها، ثم اختَر مفتاح التشفير الذي تديره Google.
  5. انقر على الزر إنشاء موضوع.

هذا هو الشكل الذي يظهر به مربّع حوار إنشاء الموضوع:

a05cfdbf64571ceb.png

والآن بعد أن أصبح لديك موضوع، يجب إنشاء اشتراك له:

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

إليك الشكل الذي تظهر به شاشة إنشاء الاشتراك:

c5444375c20b0618.jpeg

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

من سطر الأوامر

يمكن لمستخدمي خدمة "النشر/الاشتراك" إنشاء مواضيع واشتراكات باستخدام الأمرَين 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].

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

من الرمز (نص برمجي قصير بلغة Python)

يمكنك أيضًا استخدام واجهة برمجة تطبيقات Pub/Sub في رمز المصدر لبرمجة إنشاء المواضيع والاشتراكات. في ما يلي رمز النص البرمجي maker.py في مجلد Repo للوحدة 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'

إذا كنت مبتدئًا في مجال النشر/الاشتراك، يمكنك الاطّلاع على المستند التقني حول بنية النشر/الاشتراك للحصول على إحصاءات إضافية.

5- تعديل الإعدادات

تشمل التعديلات في الإعدادات كلاً من تغيير ملفات إعداد مختلفة، بالإضافة إلى إنشاء ما يعادلها من قوائم انتظار السحب في App Engine، ولكن ضمن منظومة Cloud Pub/Sub المتكاملة.

حذف playlist.yaml

نحن بصدد خروجنا من قائمة انتظار المهام تمامًا، لذا يجب حذف queue.yaml لأنّ النشر أو الاشتراك لا يستخدم هذا الملف. بدلاً من إنشاء قائمة انتظار غير مكتملة، ستنشئ موضوع نشر/اشتراكاشتراك).

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

بايثون 3

بالنسبة إلى مستخدمي Python 3 وapp.yaml، الهدف الأساسي هو إزالة العناصر. في هذا القسم، ستحذف القسم handlers والتوجيهَين threadsafe وapi_version، ولن تنشئ قسم libraries.

لا توفّر بيئات تشغيل الجيل الثاني مكتبات جهات خارجية مضمَّنة، لذلك لا يلزم توفير قسم libraries في app.yaml. بالإضافة إلى ذلك، لم يعُد من المطلوب النسخ (أي ما يُعرف أحيانًا بالمورّدين أو التجميع الذاتي) غير المُدمَجة في الحِزم التابعة لجهات خارجية. يجب فقط إدراج مكتبات الجهات الخارجية التي يستخدمها تطبيقك في requirements.txt.

يهدف القسم handlers في app.yaml إلى تحديد معالِجات التطبيق (script) والملفات الثابتة للملفات. بما أنّ وقت تشغيل Python 3 يتطلب أُطر عمل الويب لتنفيذ عمليات التوجيه الخاصة بها، يجب تغيير جميع معالِجات النصوص البرمجية إلى auto. إذا كان تطبيقك (مثل الوحدة 18) لا يعرض ملفات ثابتة، ستكون جميع المسارات auto، ما يجعلها غير ذات صلة. نتيجةً لذلك، لن يكون القسم handlers مطلوبًا أيضًا، لذا احذفه.

وأخيرًا، لا يتم استخدام التوجيه threadsafe أو api_version في بايثون 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 في المجلد Module 19 repo. إذا أردت استخدام ذلك بدلاً من ذلك في عمليات النشر، تأكَّد من إلحاق اسم الملف هذا بنهاية الأمر: gcloud app deploy app3.yaml (وإلا سيتم استخدام تطبيقك تلقائيًا ونشره من خلال ملف Python 2 app.yaml الذي لم يتم تغييره).

appengine_config.py

في حال الترقية إلى Python 3، ما مِن حاجة إلى استخدام appengine_config.py، لذا احذفها. السبب ليس ضروريًا أنّ دعم المكتبات التابعة لجهات خارجية يتطلّب فقط تحديدها في requirements.txt. مستخدمي Python 2، واصل القراءة.

تحتوي الوحدة 18 appengine_config.py على الرمز البرمجي المناسب للتوافق مع المكتبات التابعة لجهات خارجية، مثل مكتبات فلاسك ومكتبات برامج 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"، يمكنك حذفه. إذا كنت تستخدم Python 2، عليك إضافة ملء المجلد lib باستخدام الأمر التالي:

pip install -t lib -r requirements.txt  # or pip2

في حال تثبيت Python 2 و3 على نظام التطوير الذي تستخدمه، قد تحتاج إلى استخدام pip2 بدلاً من pip.

6- تعديل رمز التطبيق

يعرض هذا القسم تعديلات على ملف التطبيق الرئيسي، main.py، وستحلّ محلّ استخدام قوائم انتظار مهام App Engine (Cloud Pub/Sub). ليست هناك أي تغييرات على نموذج الويب، templates/index.html. يجب أن يعمل كلا التطبيقين بشكل متطابق وأن يعرضا البيانات نفسها.

تحديث عمليات الاستيراد والإعداد

هناك عدة تعديلات على عمليات الاستيراد والإعداد:

  1. بالنسبة إلى عمليات الاستيراد، يجب استبدال App Engine NDB وقائمة انتظار المهام بـ Cloud NDB وPub/Sub.
  2. إعادة تسمية pullq من اسم QUEUE إلى اسم TOPIC
  3. عند استخدام مهام السحب، أجَر العاملون هذه المهام لمدة ساعة، ولكن عند استخدام أسلوب النشر/الاشتراك، يتم قياس المُهل على أساس كل رسالة، لذا احذف ثابت HOUR.
  4. تتطلب واجهات برمجة التطبيقات في السحابة الإلكترونية استخدام برنامج واجهة برمجة تطبيقات، لذا يجب بدء تلك الخدمات لكل من Cloud NDB وCloud Pub/Sub، ما يوفر للعملاء المواضيع والاشتراكات معًا.
  5. تتطلّب ميزة النشر/الاشتراك رقم تعريف المشروع على السحابة الإلكترونية، لذا عليك استيراده والحصول عليه من google.auth.default().
  6. يتطلب نشر/اشتراك "أسماء مسارات مؤهلة بالكامل" للمواضيع والاشتراكات، لذا أنشئها باستخدام وظائف تسهيل الاستخدام "*_path()".

في ما يلي عمليات الاستيراد والتهيئة من الوحدة 18 متبوعة بالطريقة التي يجب أن تعتني بها الأقسام بعد تنفيذ التغييرات أعلاه، مع كون معظم الرمز الجديد موارد نشر/اشتراك مختلفة:

قبل:

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". يتطلب الوصول إلى مخزن البيانات استخدامًا صريحًا لمدير سياق عميل Cloud NDB API، وهو ds_client.context(). في الرموز البرمجية، يعني ذلك إكمال استدعاءات Datastore في كل من store_visit() وfetch_visits() داخل مجموعات Python with. وهذا التحديث مماثل لما ورد في الوحدة 2.

التغيير الأكثر صلة بالنسبة إلى النشر/الاشتراك هو استبدال مهمة السحب في قائمة انتظار المهام بنشر رسالة نشر/اشتراك في الموضوع 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"، ويستخدم fetch_counts() باستثناء تضمين طلب بحث "مخزن البيانات" داخل مجموعة 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 قائمة الانتظار مع Pub/Sub، ولكن يظل سير العمل كما هو.

  1. أغلِق طلبات تخزين البيانات في كتلة "مدير سياق Cloud NDB" with.
  2. يتضمن تنظيف قائمة انتظار المهام حذف جميع المهام من قائمة انتظار السحب. باستخدام نشر/اشتراك، "معرّفات الإقرار" يتم جمعها في acks ثم يتم حذفها أو الإقرار بها في النهاية.
  3. يتم تأجير مهام السحب في قائمة انتظار المهام بطريقة مماثلة يتم سحبها من خلال رسائل Pub/Sub. أثناء تنفيذ حذف مهام السحب باستخدام كائنات المهام نفسها، يتم حذف رسائل النشر/الاشتراك من خلال معرّفات الإقرارات الخاصة بها.
  4. تتطلّب حمولات رسائل 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، باستثناء أنك قد استبدلت آلية وضع قائمة الانتظار الأساسية بالكامل بنجاح:

b667551dcbab1a09.png

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

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

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

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

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

  • تتضمّن المكوّنات المختلفة لخدمة Cloud Pub/Sub فئة مجانية. تحديد الاستخدام الإجمالي للحصول على فكرة أفضل عن الآثار المترتبة على التكلفة والاطّلاع على صفحة الأسعار للحصول على مزيد من التفاصيل.
  • يتم تقديم خدمة مخزن بيانات App Engine من خلال Cloud Datastore (Cloud Firestore في وضع "مخزن البيانات") التي توفّر أيضًا فئة مجانية. يمكنك الاطّلاع على صفحة الأسعار لمزيد من المعلومات.

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

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

لم يعد App Engine النظام الأساسي الوحيد بدون خوادم في Google Cloud. إذا كان لديك تطبيق App Engine صغير أو تطبيق ذو وظائف محدودة وتريد تحويله إلى خدمة مصغّرة مستقلة، أو إذا كنت تريد تقسيم تطبيق متجانس إلى عدة مكوّنات قابلة لإعادة الاستخدام، هذه هي الأسباب الوجيهة للانتقال إلى وظائف السحابة الإلكترونية. إذا أصبحت عملية التطوير جزءًا من سير عمل تطوير التطبيقات، خاصةً إذا كانت تتألف من مسار CI/CD (التكامل المستمر أو العرض أو النشر المستمر)، ننصحك بنقل البيانات إلى تشغيل السحابة الإلكترونية. تغطي الوحدات التالية هذه السيناريوهات:

  • نقل البيانات من App Engine إلى Cloud Functions: راجِع الوحدة 11.
  • نقل البيانات من App Engine إلى Cloud Run: راجِع الوحدة 4 لتضمين تطبيقك مع Docker، أو الوحدة 5 لتنفيذ ذلك بدون حاويات أو معلومات Docker أو Dockerfiles.

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

بغض النظر عن وحدة نقل البيانات التي تفكر فيها بعد ذلك، يمكن الوصول إلى كل محتوى محطة النقل بدون خادم (الدروس التطبيقية حول الترميز والفيديوهات ورمز المصدر [عند توفّره]) من خلال مستودع البرامج المفتوحة المصدر. يوفّر README الخاص بالمستودع أيضًا إرشادات حول عمليات نقل البيانات التي يجب أخذها في الاعتبار وأي "طلب" ذي صلة. لوحدات النقل.

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

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

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

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

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

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

Codelab

Python 2

Python 3

الوحدة 18

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

(لا ينطبق)

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

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

(مثل لغة Python 2 باستثناء استخدام app3.yaml ما لم يتم تحديث app.yaml كما هو موضَّح أعلاه)

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

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

قائمة مهام App Engine

خدمة Cloud Pub/Sub

NDB وCloud NDB (مخزن بيانات) في App Engine

منصة App Engine

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

الفيديوهات

الترخيص

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