1. نظرة عامة
تهدف سلسلة الدروس التطبيقية حول الترميز بدون خادم (البرامج التعليمية العملية) والفيديوهات ذات الصلة إلى مساعدة مطوّري Google Cloud الذين لا يستخدمون خوادم على تحديث تطبيقاتهم من خلال إرشادهم خلال عملية واحدة أو أكثر من عمليات نقل البيانات، بعيدًا عن الخدمات القديمة في المقام الأول. يؤدي ذلك إلى تسهيل حمل التطبيقات وتوفير المزيد من الخيارات والمرونة، ما يتيح لك الدمج مع مجموعة أكبر من منتجات Cloud والوصول إليها والترقية بسهولة إلى الإصدارات الأحدث باللغات. مع تركيزنا في البداية على مستخدمي Cloud الأوائل، لا سيما مطوّري App Engine (البيئة العادية)، فإنّ هذه السلسلة واسعة بما يكفي لتشمل أنظمة أساسية أخرى بدون خادم، مثل Cloud Functions وCloud Run أو أي منصة أخرى إن وُجدت.
يهدف هذا الدرس التطبيقي إلى نقل نموذج Module 8 إلى لغة Python 3، بالإضافة إلى نقل إذن الوصول إلى Datastore (Cloud Firestore في وضع "مخزن البيانات") من استخدام Cloud NDB إلى مكتبة برامج Cloud Datastore الأصلية والترقية إلى أحدث إصدار من مكتبة عملاء Cloud Tasks.
أضفنا استخدام قائمة انتظار المهام لمهام push في الوحدة 7، ثم نقلنا هذا الاستخدام إلى مهام Cloud في الوحدة 8. هنا في الوحدة 9، ننتقل إلى بايثون 3 وCloud Datastore. سيتم نقل بيانات المستخدمين الذين يستخدمون قوائم انتظار المهام لتنفيذ المهام السحب إلى Cloud Pub/Sub، ويجب الرجوع إلى الوحدات من 18 إلى 19 بدلاً من ذلك.
ستتعرَّف على كيفية إجراء ما يلي:
- نقل نموذج تطبيق الوحدة 8 إلى بايثون 3
- تبديل الوصول إلى تخزين البيانات من Cloud NDB إلى مكتبات عملاء Cloud NDB
- الترقية إلى أحدث إصدار من مكتبة برامج "مهام Google"
المتطلبات
- مشروع Google Cloud Platform مع حساب فوترة نشط على Google Cloud Platform
- المهارات الأساسية في لغة بايثون
- المعرفة العملية بأوامر نظام التشغيل Linux الشائعة
- معرفة أساسية حول تطوير ونشر تطبيقات App Engine
- تطبيق App Engine صالح للوحدة 8: أكمِل الدرس التطبيقي حول ترميز الوحدة 8 (يُنصح به) أو انسخ تطبيق الوحدة 8 من المستودع.
استطلاع
كيف ستستخدم هذا البرنامج التعليمي؟
كيف تقيّم تجربتك مع Python؟
ما هو تقييمك لتجربتك في استخدام خدمات Google Cloud؟
2. الخلفية
توضح الوحدة 7 كيفية استخدام مهام إرسال المهام في قائمة انتظار مهام App Engine في تطبيقات Python 2 Flask App Engine. في الوحدة 8، يمكنك نقل هذا التطبيق من قائمة انتظار المهام إلى "مهام السحابة الإلكترونية". في الوحدة 9، يمكنك متابعة تلك الرحلة ونقل ذلك التطبيق إلى Python 3 بالإضافة إلى نقل إمكانية الوصول إلى Datastore من استخدام Cloud NDB إلى مكتبة عملاء Cloud NDB الأصلية.
بما أن Cloud NDB يعمل مع كل من بايثون 2 و3، فإنه يكفي لمستخدمي App Engine نقل تطبيقاتهم من الإصدار 2 إلى 3 من Python. إنّ النقل الإضافي لمكتبات العملاء إلى "مخزن البيانات في السحابة الإلكترونية" هو اختياري تمامًا، وهناك سبب واحد فقط لأخذ هذا في الاعتبار: إذا كانت لديك تطبيقات غير تابعة لـ App Engine (و/أو تطبيقات Python 3 App Engine) تستخدم مكتبة برامج "تخزين البيانات في السحابة الإلكترونية" وتريد دمج قاعدة الرموز الخاصة بك للوصول إلى "مخزن البيانات" باستخدام مكتبة برامج واحدة فقط. تم إنشاء Cloud NDB خصيصًا لمطوّري Python 2 App Engine كأداة لنقل البيانات Python 3، لذا إذا لم يكن لديك رمز برمجي يستخدم مكتبة عملاء Cloud Datastore، ليس عليك التفكير في عملية النقل هذه.
وفي الختام، يستمر تطوير مكتبة عملاء Cloud Tasks فقط في لغة بايثون 3، ولذلك نقوم "بنقل البيانات" من إحدى النسخ النهائية من Python 2 إلى Python 3 المعاصرة. لحسن الحظ، لم يتم إجراء أي تغييرات قد تؤدي إلى أعطال في بايثون 2، ما يعني أنّه لا داعي لاتخاذ أي إجراء.
يتضمن هذا الدليل التوجيهي الخطوات التالية:
- الإعداد/التمهيد
- تعديل الإعدادات
- تعديل رمز التطبيق
3- الإعداد/التمهيد
يوضّح هذا القسم كيفية تنفيذ ما يلي:
- إعداد مشروعك على Google Cloud
- الحصول على نموذج تطبيق أساسي
- (إعادة) نشر التطبيق الأساسي والتحقّق من صحته
تضمن هذه الخطوات بدء استخدام رمز صالح ومن استعداده لنقل البيانات إلى خدمات السحابة الإلكترونية.
1. إعداد المشروع
إذا أكملت الدرس التطبيقي حول ترميز الوحدة 8، أعِد استخدام المشروع نفسه (والرمز البرمجي). ويمكنك بدلاً من ذلك إنشاء مشروع جديد أو إعادة استخدام مشروع حالي آخر. تأكَّد من أنّ المشروع يتضمّن حساب فوترة نشطًا وتطبيق App Engine مفعَّل. ابحث عن رقم تعريف مشروعك عندما تحتاج إلى أن يكون في متناول يدك خلال هذا الدرس التطبيقي حول الترميز، واستخدِمه كلما صادفت المتغيّر PROJECT_ID
.
2. الحصول على نموذج تطبيق أساسي
ويتمثّل أحد المتطلّبات الأساسية في تطبيق Module 8 App Engine قيد التشغيل: أكمل الدرس التطبيقي حول الترميز الخاص بالوحدة 8 (يُنصح به) أو انسخ تطبيق الوحدة 8 من المستودع. وسواء كنت تستخدم موقعك أو يديك، فإن رمز الوحدة 8 هو المكان الذي سنبدأ فيه ("البدء"). يرشدك هذا الدرس التطبيقي حول الترميز خلال عملية النقل، وختامًا باستخدام رمز يشبه ما هو في مجلد Repo للوحدة 9 ("FINISH").
- START: مستودع الوحدة 8
- إنهاء: مستودع الوحدة 9
- المستودع بالكامل (نسخة طبق الأصل أو تنزيل ملف ZIP)
بغض النظر عن تطبيق الوحدة 7 الذي تستخدمه، يجب أن يبدو المجلد كما يلي، على الأرجح مع مجلد lib
أيضًا:
$ ls README.md appengine_config.py requirements.txt app.yaml main.py templates
3- (إعادة) نشر التطبيق الأساسي والتحقّق من صحته
نفِّذ الخطوات التالية لنشر تطبيق الوحدة 8:
- احذف المجلد "
lib
" في حال توفّره وشغِّلpip install -t lib -r requirements.txt
لإعادة تعبئة "lib
". قد تحتاج إلى استخدامpip2
بدلاً من ذلك في حال تثبيت Python 2 و3 على جهاز التطوير. - تأكَّد من تثبيت أداة سطر الأوامر
gcloud
وإعدادها ومراجعة استخدامها. - (اختياري) يمكنك ضبط مشروعك على Google Cloud باستخدام
gcloud config set project
PROJECT_ID
في حال كنت لا تريد إدخالPROJECT_ID
مع كل أمرgcloud
تصدره. - نشر نموذج التطبيق باستخدام "
gcloud app deploy
" - تأكَّد من أنّ التطبيق يعمل على النحو المتوقّع بدون أي مشكلة. إذا أكملت الدرس التطبيقي حول ترميز الوحدة 8، سيعرض التطبيق أهم الزوّار إلى جانب أحدث الزيارات (الموضّحة أدناه). يظهر في أسفل الصفحة إشارة إلى المهام القديمة التي سيتم حذفها.
4. تعديل الإعدادات
requirements.txt
العنصر requirements.txt
الجديد مماثل تقريبًا للوحدة النمطية 8 مع تغيير كبير واحد: استبدل google-cloud-ndb
بـ google-cloud-datastore
. أجرِ هذا التغيير حتى يظهر ملف requirements.txt
على النحو التالي:
flask
google-cloud-datastore
google-cloud-tasks
لا يحتوي ملف requirements.txt
هذا على أي أرقام إصدارات، ما يعني أنّه تم اختيار أحدث النُسخ. في حال ظهور أي حالات عدم توافق، يكون استخدام أرقام الإصدارات لتثبيت إصدارات العمل للتطبيق هو ممارسة عادية.
app.yaml
إنّ الجيل الثاني من بيئة تشغيل App Engine لا يتوافق مع مكتبات تابعة لجهات خارجية مدمجة، مثل مكتبات 2.x، ولا يتيح أيضًا نسخ المكتبات غير المدمَجة. الشرط الوحيد للحِزم التابعة لجهات خارجية هو إدراجها في requirements.txt
. نتيجةً لذلك، يمكن حذف قسم libraries
بالكامل من app.yaml
.
وهناك تحديث آخر وهو أن وقت تشغيل Python 3 يتطلب استخدام أطر عمل على الويب تقوم بالتوجيه الخاص. نتيجةً لذلك، يجب تغيير جميع معالِجات النص البرمجي إلى auto
. ومع ذلك، نظرًا لأنه يجب تغيير جميع المسارات إلى auto
، وليست هناك ملفات ثابتة يتم عرضها من نموذج التطبيق هذا، ليس من الضروري أن يكون لديك أي معالِجات، لذا عليك إزالة قسم handlers
بالكامل أيضًا.
الشيء الوحيد المطلوب في app.yaml
هو ضبط بيئة التشغيل على إصدار متوافق من Python 3، لنفترض 3.10. أجرِ هذا التغيير بحيث يصبح الاسم الجديد والمختصر app.yaml
هو السطر المفرد فقط:
runtime: python310
احذف appengine_config.py وlib
الجيل التالي من بيئات تشغيل App Engine يجدد استخدام الحزمة التابعة لجهة خارجية:
- المكتبات المدمجة هي المكتبات التي تحققت منها Google وتم توفيرها على خوادم App Engine، ويرجع ذلك على الأرجح إلى احتواءها على رمز C/C++ لا يُسمَح للمطوّرين بنشره على السحابة الإلكترونية، ولم تعُد هذه المكتبات متاحة في بيئات تشغيل الجيل الثاني.
- لم تعُد هناك حاجة إلى نسخ المكتبات غير المضمّنة (تُسمّى أحيانًا "التوريد" أو "التجميع الذاتي") في بيئات تشغيل الجيل الثاني. وبدلاً من ذلك، يجب إدراجها في
requirements.txt
حيث يثبّتها نظام الإصدار تلقائيًا نيابةً عنك في وقت النشر.
ونتيجةً لهذه التغييرات التي طرأت على إدارة الحِزم التابعة لجهات خارجية، لا حاجة إلى ملف appengine_config.py
أو مجلد lib
، لذا يُرجى حذفهما. في بيئات تشغيل الجيل الثاني، يثبِّت App Engine تلقائيًا حِزم الجهات الخارجية المدرَجة في requirements.txt
. التلخيص:
- عدم توفّر مكتبات تابعة لجهات خارجية مجمّعة بشكل ذاتي أو منسوخة إدراجهم في
requirements.txt
- لا يتم حفظ
pip install
في مجلد "lib
"، ما يعني أنّه ما مِن مدة للمجلد "lib
". - عدم توفّر مكتبات تابعة لجهات خارجية مضمّنة (بدون قسم
libraries
) فيapp.yaml
إدراجهم فيrequirements.txt
- ما مِن مكتبات تابعة لجهات خارجية يمكن الرجوع إليها من تطبيقك، ما يعني عدم توفُّر ملف
appengine_config.py
.
الشرط الوحيد للمطوّر هو إدراج جميع مكتبات الجهات الخارجية المطلوبة في requirements.txt
.
5- تحديث ملفات التطبيق
هناك ملف تطبيق واحد فقط، main.py
، لذا تؤثر جميع التغييرات في هذا القسم في هذا الملف فقط. فيما يلي "الاختلافات" توضيح للتغييرات الشاملة التي يجب إجراؤها لإعادة تضمين الرمز الحالي في التطبيق الجديد. ولا يُتوقع من القراء قراءة التعليمات البرمجية سطرًا تلو الآخر، حيث إن الغرض منها هو ببساطة الحصول على نظرة عامة تصويرية لما هو مطلوب في عملية إعادة الضبط هذه (ولكن يمكنك فتح الرمز في علامة تبويب جديدة أو تنزيله والتكبير إذا رغبت في ذلك).
تحديث عمليات الاستيراد والإعداد
إنّ قسم الاستيراد في "main.py
" للوحدة 8 يستخدم Cloud NDB وCloud Tasks. يجب أن يبدو على النحو التالي:
قبل:
from datetime import datetime
import json
import logging
import time
from flask import Flask, render_template, request
import google.auth
from google.cloud import ndb, tasks
app = Flask(__name__)
ds_client = ndb.Client()
ts_client = tasks.CloudTasksClient()
يتم تبسيط التسجيل وتحسينه في بيئات تشغيل الجيل الثاني مثل Python 3:
- للحصول على تجربة تسجيل شاملة، يُرجى استخدام Cloud Logging
- لتسجيل الدخول بسهولة، ما عليك سوى الإرسال إلى
stdout
(أوstderr
) عبرprint()
- لست بحاجة إلى استخدام وحدة
logging
بلغة Python (لذا عليك إزالتها)
وبناءً على ذلك، يجب حذف استيراد logging
وتبديل google.cloud.ndb
بـ google.cloud.datastore
. وبالمثل، يمكنك تغيير ds_client
للإشارة إلى عميل مخزن البيانات بدلاً من عميل NDB. بعد إجراء هذه التغييرات، سيبدو الجزء العلوي من تطبيقك الجديد على النحو التالي:
بعد:
from datetime import datetime
import json
import time
from flask import Flask, render_template, request
import google.auth
from google.cloud import datastore, tasks
app = Flask(__name__)
ds_client = datastore.Client()
ts_client = tasks.CloudTasksClient()
نقل البيانات إلى "مخزن البيانات في السحابة الإلكترونية"
حان الوقت الآن لاستبدال استخدام مكتبة عملاء NDB بـ Datastore. يتطلب كل من App Engine NDB وCloud NDB نموذج بيانات (فئة). مساحة التخزين لهذا التطبيق هي Visit
. تعمل الوظيفة store_visit()
بالطريقة نفسها في جميع وحدات نقل البيانات الأخرى، إذ يتم تسجيل الزيارة من خلال إنشاء سجلّ Visit
جديد، مع حفظ عنوان IP للعميل الذي تتم زيارته ووكيل المستخدم الخاص به (نوع المتصفّح).
قبل:
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 entity in Datastore'
with ds_client.context():
Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
مع ذلك، لا تستخدم خدمة "تخزين البيانات في السحابة الإلكترونية" فئة نموذج بيانات، لذا احذف الفئة. علاوةً على ذلك، لا تنشئ خدمة "تخزين البيانات في السحابة الإلكترونية" طابعًا زمنيًا تلقائيًا عند إنشاء السجلات، ما يتطلب منك إجراء ذلك يدويًا، ويتم إجراء ذلك من خلال استدعاء datetime.now()
.
بدون فئة البيانات، من المفترض أن تظهر قيمة store_visit()
المعدَّلة على النحو التالي:
بعد:
def store_visit(remote_addr, user_agent):
'create new Visit entity in Datastore'
entity = datastore.Entity(key=ds_client.key('Visit'))
entity.update({
'timestamp': datetime.now(),
'visitor': '{}: {}'.format(remote_addr, user_agent),
})
ds_client.put(entity)
الدالة الأساسية هي fetch_visits()
. فهي لا تُجري طلبات البحث الأصلية فحسب لأحدث Visit
، بل إنّها أيضًا تحصل على الطابع الزمني لآخر Visit
معروضة وتنشئ مهمة إرسال تطلب /trim
(وبالتالي trim()
) لحذف قيم Visit
القديمة بشكل جماعي. هنا نستخدم Cloud NDB:
قبل:
def fetch_visits(limit):
'get most recent visits & add task to delete older visits'
with ds_client.context():
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)
task = {
'app_engine_http_request': {
'relative_uri': '/trim',
'body': json.dumps({'oldest': oldest}).encode(),
'headers': {
'Content-Type': 'application/json',
},
}
}
ts_client.create_task(parent=QUEUE_PATH, task=task)
return (v.to_dict() for v in data), oldest_str
التغييرات الأساسية:
- استبدال طلب NDB على السحابة الإلكترونية بنموذج "مخزن البيانات في السحابة الإلكترونية" تختلف أنماط الاستعلام قليلاً.
- لا يتطلب "مخزن البيانات" استخدام مدير سياق، ولا يسمح باستخراج بياناته (باستخدام
to_dict()
) على النحو الذي يفعله Cloud NDB. - استبدال مكالمات التسجيل بـ
print()
بعد هذه التغييرات، سيبدو fetch_visits()
على النحو التالي:
بعد:
def fetch_visits(limit):
'get most recent visits & add task to delete older visits'
query = ds_client.query(kind='Visit')
query.order = ['-timestamp']
visits = list(query.fetch(limit=limit))
oldest = time.mktime(visits[-1]['timestamp'].timetuple())
oldest_str = time.ctime(oldest)
print('Delete entities older than %s' % oldest_str)
task = {
'app_engine_http_request': {
'relative_uri': '/trim',
'body': json.dumps({'oldest': oldest}).encode(),
'headers': {
'Content-Type': 'application/json',
},
}
}
ts_client.create_task(parent=QUEUE_PATH, task=task)
return visits, oldest_str
عادةً ما يكون هذا كله ضروريًا. للأسف، هناك مشكلة كبيرة واحدة.
(ربما) إنشاء قائمة انتظار جديدة (دفعة)
في الوحدة 7، أضفنا استخدام App Engine taskqueue
إلى تطبيق الوحدة 1 الحالي. من بين الفوائد الرئيسية لفرض مهام الدفع كميزة قديمة في App Engine أنّ الخيار "تلقائي" سيتم إنشاء قائمة الانتظار تلقائيًا. عندما تم نقل هذا التطبيق إلى Cloud Tasks في الوحدة 8، كانت قائمة الانتظار التلقائية هذه موجودة من قبل، لذلك ما زلنا لم نكن بحاجة إلى القلق بشأنها في هذه الحالة. يتغير هذا هنا في الوحدة 9.
أحد الجوانب المهمة التي يجب مراعاتها هو أن تطبيق App Engine الجديد لم يعد يستخدم خدمات App Engine، ومن هذا المنطلق، لم يعد بإمكانك افتراض أن App Engine ينشئ تلقائيًا قائمة انتظار مهام تلقائيًا في منتج مختلف (مهام Cloud). كما هو مكتوب، سيتعذر إنشاء مهمة في fetch_visits()
(لقائمة انتظار غير موجودة). يجب توفّر دالة جديدة للتحقّق من توفُّر قائمة الانتظار ("التلقائية")، وفي حال عدم توفّرها، يمكنك إنشاء قائمة الانتظار.
استدعِ هذه الدالة _create_queue_if()
، وأضِفها إلى تطبيقك أعلى fetch_visits()
مباشرةً لأنها مكان استدعائها. نص الدالة المطلوب إضافتها:
def _create_queue_if():
'app-internal function creating default queue if it does not exist'
try:
ts_client.get_queue(name=QUEUE_PATH)
except Exception as e:
if 'does not exist' in str(e):
ts_client.create_queue(parent=PATH_PREFIX,
queue={'name': QUEUE_PATH})
return True
تتطلب دالة Cloud Tasks create_queue()
اسم المسار الكامل لقائمة الانتظار باستثناء اسم قائمة الانتظار. للتبسيط، أنشئ متغيرًا آخر PATH_PREFIX
يمثل QUEUE_PATH
مطروحًا منه اسم قائمة الانتظار (QUEUE_PATH.rsplit('/', 2)[0]
). أضِف تعريفها بالقرب من الجزء العلوي بحيث تبدو مجموعة الرموز التي تتضمّن جميع المهام الثابتة على النحو التالي:
_, PROJECT_ID = google.auth.default()
REGION_ID = 'REGION_ID' # replace w/your own
QUEUE_NAME = 'default' # replace w/your own
QUEUE_PATH = ts_client.queue_path(PROJECT_ID, REGION_ID, QUEUE_NAME)
PATH_PREFIX = QUEUE_PATH.rsplit('/', 2)[0]
عدّل الآن السطر الأخير في fetch_visits()
لاستخدام _create_queue_if()
، وأنشئ أولاً قائمة الانتظار إذا لزم الأمر، ثم أنشئ المهمة بعد ذلك:
if _create_queue_if():
ts_client.create_task(parent=QUEUE_PATH, task=task)
return visits, oldest_str
من المفترض أن يظهر كل من _create_queue_if()
وfetch_visits()
على النحو التالي:
def _create_queue_if():
'app-internal function creating default queue if it does not exist'
try:
ts_client.get_queue(name=QUEUE_PATH)
except Exception as e:
if 'does not exist' in str(e):
ts_client.create_queue(parent=PATH_PREFIX,
queue={'name': QUEUE_PATH})
return True
def fetch_visits(limit):
'get most recent visits & add task to delete older visits'
query = ds_client.query(kind='Visit')
query.order = ['-timestamp']
visits = list(query.fetch(limit=limit))
oldest = time.mktime(visits[-1]['timestamp'].timetuple())
oldest_str = time.ctime(oldest)
print('Delete entities older than %s' % oldest_str)
task = {
'app_engine_http_request': {
'relative_uri': '/trim',
'body': json.dumps({'oldest': oldest}).encode(),
'headers': {
'Content-Type': 'application/json',
},
}
}
if _create_queue_if():
ts_client.create_task(parent=QUEUE_PATH, task=task)
return visits, oldest_str
بخلاف الاضطرار إلى إضافة هذا الرمز الإضافي، فإن باقي رمز مهام Cloud في الغالب سليم من الوحدة 8. الجزء الأخير من التعليمة البرمجية الذي يجب النظر إليه هو معالج المهام.
تحديث معالِج المهام (الإشعارات الفورية)
في معالج المهام، trim()
، يطلب رمز Cloud NDB للزيارات الأقدم من الأقدم المعروضة. فهو يستخدم طلب بحث عن المفاتيح فقط لتسريع الأمور، فلماذا تجلب جميع البيانات إذا كنت تحتاج فقط إلى أرقام تعريف الزيارات؟ بعد توفُّر جميع أرقام تعريف الزيارات، يمكنك حذفها كلها في مجموعة باستخدام وظيفة delete_multi()
في Cloud NDB.
قبل:
@app.route('/trim', methods=['POST'])
def trim():
'(push) task queue handler to delete oldest visits'
oldest = float(request.get_json().get('oldest'))
with ds_client.context():
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
على غرار fetch_visits()
، شملت التغييرات الأكبر على المنصة استبدال رمز NDB في Cloud بأداة "تخزين البيانات في Cloud"، وتعديل أنماط طلبات البحث، وإزالة استخدام مدير السياق، وتغيير طلبات التسجيل إلى print()
.
بعد:
@app.route('/trim', methods=['POST'])
def trim():
'(push) task queue handler to delete oldest visits'
oldest = float(request.get_json().get('oldest'))
query = ds_client.query(kind='Visit')
query.add_filter('timestamp', '<', datetime.fromtimestamp(oldest))
query.keys_only()
keys = list(visit.key for visit in query.fetch())
nkeys = len(keys)
if nkeys:
print('Deleting %d entities: %s' % (
nkeys, ', '.join(str(k.id) for k in keys)))
ds_client.delete_multi(keys)
else:
print('No entities older than: %s' % time.ctime(oldest))
return '' # need to return SOME string w/200
ما من تغييرات على المعالج الرئيسي للتطبيقات root()
.
المنفذ إلى Python 3
تم تصميم نموذج التطبيق هذا للتشغيل على كل من Python 2 وPython. تمت تغطية أي تغييرات خاصة بـ Python 3 في وقت سابق في الأقسام ذات الصلة من هذا البرنامج التعليمي. ما مِن خطوات إضافية أو مكتبات توافق مطلوبة.
تحديث "مهام Google"
الإصدار النهائي من مكتبة برامج Cloud Tasks الذي يدعم Python 2 هو 1.5.0. في وقت كتابة هذا التقرير، كان الإصدار الأحدث من مكتبة البرامج للغة Python 3 متوافقًا تمامًا مع هذا الإصدار، وبالتالي لا يلزم إجراء أي تحديثات إضافية.
تعديل نموذج HTML
لا يلزم إجراء أي تغييرات في ملف نموذج HTML، templates/index.html
أيضًا، لذلك يلخّص هذا الإجراء جميع التغييرات اللازمة للوصول إلى تطبيق الوحدة 9.
6- الملخّص/تنظيف البيانات
نشر التطبيق والتحقق منه
بعد إكمال تعديلات الرمز، وتحديدًا المنفذ إلى Python 3، انشر تطبيقك باستخدام gcloud app deploy
. يجب أن يكون الناتج متطابقًا مع التطبيقات المتوفّرة في تطبيق الوحدتَين 7 و8 باستثناء أنّك نقلت إذن الوصول إلى قاعدة البيانات إلى مكتبة عملاء Cloud Datastore وأجرِ الترقية إلى Python 3:
تكمل هذه الخطوة الدرس التطبيقي حول الترميز. ندعوك إلى مقارنة الرمز الخاص بك بما هو موجود في مجلد الوحدة 9. تهانينا!
تَنظيم
بنود عامة
إذا كنت قد انتهيت الآن، ننصحك بإيقاف تطبيق 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 Tasks فئة مجانية. يمكنك الاطّلاع على صفحة الأسعار لمزيد من التفاصيل.
- يتم تقديم خدمة مخزن بيانات App Engine من خلال Cloud Datastore (Cloud Firestore في وضع "مخزن البيانات") التي توفّر أيضًا فئة مجانية. يمكنك الاطّلاع على صفحة الأسعار لمزيد من المعلومات.
الخطوات التالية
وبهذا نكون قد انتهينا من إرسال مهام الدفع في قائمة انتظار مهام App Engine إلى Cloud Tasks. يتم أيضًا تناول عملية النقل الاختياري من Cloud NDB إلى Cloud Datastore بشكل مستقل (بدون قائمة انتظار المهام أو مهام السحابة الإلكترونية) في الوحدة 3. بالإضافة إلى الوحدة 3، هناك وحدات نقل أخرى تركز على التوقف عن استخدام خدمات App Engine القديمة التي يجب مراعاتها، وتشمل ما يلي:
- الوحدة 2: النقل من NDB في App Engine إلى Cloud NDB
- الوحدة 3: النقل من Cloud NDB إلى Cloud Datastore
- الوحدات 12-13: النقل من App Engine Memcache إلى Cloud Memorystore
- الوحدات 15-16: النقل من App Engine Blobstore إلى Cloud Storage
- الوحدات 18-19: قائمة انتظار مهام App Engine (سحب المهام) إلى Cloud Pub/Sub
لم يعد App Engine النظام الأساسي الوحيد بدون خوادم في Google Cloud. إذا كان لديك تطبيق App Engine صغير أو تطبيق ذو وظائف محدودة وتريد تحويله إلى خدمة مصغّرة مستقلة، أو إذا كنت تريد تقسيم تطبيق متجانس إلى عدة مكوّنات قابلة لإعادة الاستخدام، هذه هي الأسباب الوجيهة للانتقال إلى وظائف السحابة الإلكترونية. إذا أصبحت عملية التطوير جزءًا من سير عمل تطوير التطبيقات، خاصةً إذا كانت تتألف من مسار CI/CD (التكامل المستمر أو العرض أو النشر المستمر)، ننصحك بنقل البيانات إلى تشغيل السحابة الإلكترونية. تغطي الوحدات التالية هذه السيناريوهات:
- نقل البيانات من App Engine إلى Cloud Functions: راجِع الوحدة 11.
- نقل البيانات من App Engine إلى Cloud Run: راجِع الوحدة 4 لتضمين تطبيقك مع Docker، أو الوحدة 5 لتنفيذ ذلك بدون حاويات أو معلومات Docker أو
Dockerfile
s.
إنّ التبديل إلى نظام أساسي آخر بدون خادم هو إجراء اختياري، وننصحك بالتفكير في أفضل الخيارات لتطبيقاتك وحالات الاستخدام قبل إجراء أي تغييرات.
بغض النظر عن وحدة نقل البيانات التي تفكر فيها بعد ذلك، يمكن الوصول إلى كل محتوى محطة النقل بدون خادم (الدروس التطبيقية حول الترميز والفيديوهات ورمز المصدر [عند توفّره]) من خلال مستودع البرامج المفتوحة المصدر. يوفّر README
الخاص بالمستودع أيضًا إرشادات حول عمليات نقل البيانات التي يجب أخذها في الاعتبار وأي "طلب" ذي صلة. لوحدات النقل.
7. مراجع إضافية
المشاكل/الملاحظات في الدروس التطبيقية حول الترميز
إذا وجدت أي مشاكل في هذا الدرس التطبيقي حول الترميز، يُرجى البحث عن مشكلتك أولاً قبل ملء النموذج. روابط للبحث وإنشاء مشاكل جديدة:
موارد نقل البيانات
يمكن العثور على روابط لمجلدات repo للوحدة 8 (START) والوحدة 9 (FINISH) في الجدول أدناه. يمكن أيضًا الوصول إليها من المستودع الخاص بجميع عمليات نقل البيانات التطبيقية حول الترميز في App Engine، والتي يمكنك استنساخ ملف ZIP أو تنزيله.
Codelab | Python 2 | Python 3 |
(لا ينطبق) | ||
الوحدة 9 | (لا ينطبق) |
مراجع على الإنترنت
في ما يلي موارد على الإنترنت قد تكون ذات صلة بهذا البرنامج التعليمي:
App Engine
- مستندات App Engine
- وقت تشغيل Python 2 App Engine (بيئة عادية)
- وقت تشغيل Python 3 App Engine (بيئة عادية)
- الاختلافات بين Python 2 3 بيئات تشغيل App Engine (بيئة عادية)
- دليل نقل البيانات من الإصدار 2 إلى 3 من App Engine (البيئة العادية)
- معلومات حول الأسعار والحصص في App Engine
Cloud NDB
- مستندات NDB في Google Cloud
- مستودع NDB في Google Cloud
- معلومات أسعار تخزين البيانات في السحابة الإلكترونية
Cloud Datastore
- مستندات تخزين البيانات في Google Cloud
- مستودع بيانات Google Cloud
- معلومات أسعار تخزين البيانات في السحابة الإلكترونية
Cloud Tasks
معلومات أخرى عن السحابة الإلكترونية
- Python على Google Cloud Platform
- مكتبات برامج Google Cloud Python
- "المجانية دائمًا" في Google Cloud الفئة
- Google Cloud SDK (أداة سطر أوامر
gcloud
) - جميع مستندات Google Cloud
الترخيص
هذا العمل مرخّص بموجب رخصة المشاع الإبداعي 2.0 مع نسب العمل إلى مؤلف عام.