صورة يومية: التمرين المعملي 6 — التنسيق باستخدام سير العمل

1. نظرة عامة

في المعامل السابقة، صمّمت إصدارًا قائمًا على الحدث من تطبيق Pic-a-daily، والذي استخدم وظيفة Cloud Storage المُشغَّلة لخدمة Google Cloud لخدمة تحليل الصور، وهي حاوية شغّلتها GCS عبر نشر/اشتراك لخدمة الصور المصغّرة وEventarc لتشغيل خدمة Image Garbage Collector على Cloud Run. كانت هناك أيضًا خدمة "صورة مجمّعة" مُشغَّلة من خلال أداة جدولة مهام في السحابة الإلكترونية:

d93345bfc235f81e.png

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

b763efcbf5589747.png

المعلومات التي ستطّلع عليها

  • App Engine
  • Cloud Firestore
  • وظائف السحابة الإلكترونية
  • Cloud Run
  • Workflows

2. الإعداد والمتطلبات

إعداد بيئة ذاتية

  1. سجِّل الدخول إلى Cloud Console وأنشِئ مشروعًا جديدًا أو أعِد استخدام مشروع حالي. (إذا لم يكن لديك حساب على Gmail أو Google Workspace، عليك إنشاء حساب.)

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

يُرجى تذكُّر رقم تعريف المشروع، وهو اسم فريد في جميع مشاريع Google Cloud (سبق أن تم استخدام الاسم أعلاه ولن يكون مناسبًا لك). ستتم الإشارة إليها لاحقًا في هذا الدرس التطبيقي حول الترميز باسم PROJECT_ID.

  1. بعد ذلك، عليك تفعيل الفوترة في Cloud Console لاستخدام موارد Google Cloud.

إنّ تنفيذ هذا الدرس التطبيقي حول الترميز لن يكون مكلفًا أو مكلفًا على الإطلاق. احرص على اتّباع أي تعليمات في قسم "الحذف سريعًا". الذي يقدم لك نصائح حول كيفية إيقاف تشغيل الموارد حتى لا تتكبّد أي فواتير خارج نطاق هذا البرنامج التعليمي. يكون مستخدمو Google Cloud الجدد مؤهَّلون للانضمام إلى برنامج فترة تجريبية مجانية بقيمة 300 دولار أمريكي.

بدء Cloud Shell

مع أنّه يمكن إدارة Google Cloud عن بُعد من الكمبيوتر المحمول، ستستخدم في هذا الدرس التطبيقي Google Cloud Shell، وهي بيئة سطر أوامر يتم تشغيلها في السحابة الإلكترونية.

من وحدة تحكّم Google Cloud Platform، انقر على رمز Cloud Shell في شريط الأدوات العلوي الأيسر:

bce75f34b2c53987.png

من المفترَض أن تستغرق عملية إدارة الحسابات والاتصال بالبيئة بضع لحظات فقط. عند الانتهاء، من المفترض أن يظهر لك شيء مثل هذا:

f6ef2b5f13479f3a.png

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

3- مقدمة عن سير العمل

90fcd42d556e310e.jpeg

يمكنك استخدام سير العمل لإنشاء مهام سير عمل بدون خادم تربط سلسلة من المهام بدون خادم معًا بالترتيب الذي تحدِّده. يمكنك الجمع بين قوة واجهات برمجة التطبيقات في Google Cloud، والمنتجات بدون خادم، مثل Cloud Functions وCloud Run، والاتصال بواجهات برمجة التطبيقات الخارجية لإنشاء تطبيقات مرنة بدون خوادم.

وفقًا لما قد تتوقعه من منسّق، تتيح لك Workflows تحديد سير العمل المنطقي في نشاطك التجاري باستخدام لغة تعريف لسير العمل مستندة إلى YAML/JSON، كما توفر واجهة برمجة تطبيقات تنفيذ سير العمل وواجهة مستخدم سير العمل لتشغيل تلك التدفقات.

وهي أكثر من مجرد تنسيق مع هذه الميزات المضمنة والقابلة للتهيئة:

  • إجراء مرن لإعادة المحاولة ومعالجة الأخطاء بين الخطوات لتنفيذ الخطوات بشكل موثوق.
  • تحليل JSON وتمرير المتغيّرات بين الخطوات لتجنُّب استخدام الرموز الملتصقة.
  • تسمح صيغ التعبيرات للقرارات بتنفيذ الخطوات الشرطية.
  • سير العمل الفرعي لسير العمل المقسّم إلى الوحدات والقابلة لإعادة الاستخدام.
  • يسمح دعم الخدمات الخارجية بتنظيم الخدمات خارج Google Cloud.
  • دعم المصادقة لخدمات Google Cloud والخدمات الخارجية لعمليات تنفيذ الخطوات الآمنة.
  • موصِّلات لخدمات Google Cloud، مثل Pub/Sub وFirestore و"مهام Google" و"المدير السري" لمزيد من السهولة في الدمج.

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

4. تفعيل واجهات برمجة التطبيقات

في هذا التمرين المعملي، سوف تربط خدمات Cloud Functions وCloud Run بخدمات سير العمل. وستستخدم أيضًا App Engine وCloud Build وVision API وخدمات أخرى.

في Cloud Shell، تأكَّد من تفعيل جميع الخدمات اللازمة:

gcloud services enable \
  appengine.googleapis.com \
  cloudbuild.googleapis.com \
  cloudfunctions.googleapis.com \
  compute.googleapis.com \
  firestore.googleapis.com \
  run.googleapis.com \
  vision.googleapis.com \
  workflows.googleapis.com \

بعد مرور بعض الوقت، من المفترض أن تنتهي العملية بنجاح:

Operation "operations/acf.5c5ef4f6-f734-455d-b2f0-ee70b5a17322" finished successfully.

5- الحصول على الرمز‏

احصل على الرمز إذا لم يسبق لك ذلك في الدروس التطبيقية السابقة للرموز:

git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop

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

frontend
 |
workflows
 |
 ├── functions
 ├── |── trigger-workflow
 ├── |── vision-data-transform
 ├── services
 ├── |── collage
 ├── |── thumbnails
 ├── workflows.yaml

في ما يلي المجلدات ذات الصلة:

  • يحتوي frontend على الواجهة الأمامية App Engine التي سنعيد استخدامها من التمرين المعملي 4.
  • يحتوي functions على دوال السحابة الإلكترونية التي تم إنشاؤها لسير العمل.
  • يحتوي services على خدمات "تشغيل السحابة الإلكترونية" المعدَّلة في "سير العمل".
  • workflows.yaml هو ملف تعريف سير العمل.

6- استكشاف ملف Workflows YAML

تحدد workflows.yaml سير العمل في سلسلة من الخطوات. لنتصفحها لفهمها بشكل أفضل.

في بداية سير العمل، هناك بعض المَعلمات التي يتم تمريرها. سيتم تمرير هذه البيانات من خلال دالتَي السحابة الإلكترونية تؤديان إلى تفعيل "سير العمل". سنصل إلى هذه الدوال لاحقًا ولكن هذه هي الطريقة التي تبدأ بها سير العمل:

d44a5e18aa9d4660.png

في ترميز YAML، يمكنك ملاحظة أنّه تم تخصيص هذه المَعلمات للمتغيّرات في الخطوة init، مثل أسماء الملفات والحِزم التي تؤدي إلى ظهور الحدث وعناوين URL لبعض دوال السحابة الإلكترونية وخدمات تشغيل السحابة الإلكترونية التي ستطلبها Workflows:

main:
  params: [args]
  steps:
    - init:
        assign:
          - file: ${args.file}
          - bucket: ${args.bucket}
          - gsUri: ${"gs://" + bucket + "/" + file}
          - projectId: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
          - urls: ${args.urls}

بعد ذلك، تتحقق Workflows من نوع الحدث. هناك نوعان من الأحداث المتوافقة: object.finalize (يتم إصداره عند حفظ ملف في حزمة التخزين في السحابة الإلكترونية) وobject.delete (يتم إصداره عند حذف ملف). ستؤدي أي تغييرات أخرى إلى ظهور استثناء غير متوافق مع الحدث.

dd1f450983655619.png

إليك الخطوة، في تعريف سير عمل YAML، حيث نتحقق من نوع حدث تخزين الملف:

    - eventTypeSwitch:
        switch:
            - condition: ${args.eventType == "google.storage.object.finalize"}
              next: imageAnalysisCall
            - condition: ${args.eventType == "google.storage.object.delete"}
              next: pictureGarbageCollectionGCS
    - eventTypeNotSupported:
        raise: ${"eventType " + args.eventType + " is not supported"}
        next: end

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

سنُلقي الآن نظرة على imageAnalysisCall. هذه سلسلة من الطلبات من Workflows لطلب واجهة برمجة تطبيقات Vision لتحليل الصورة، وتحويل بيانات الاستجابة إلى Vision API لتصنيف العناصر التي تم التعرّف عليها في الصورة، واختيار الألوان السائدة، والتحقّق من مدى أمان الصورة، ثم حفظ البيانات الوصفية في Cloud Firestore.

تجدر الإشارة إلى أنّ كل الإجراءات يتمّ تنفيذها في Workflows باستثناء Vision Transform Functions (التي سننشرها لاحقًا):

ca2ad16b9cbb436.png

هذا هو كيف تبدو الخطوات في YAML:

    - imageAnalysisCall:
        call: http.post
        args:
          url: https://vision.googleapis.com/v1/images:annotate
          headers:
            Content-Type: application/json
          auth:
            type: OAuth2
          body:
            requests:
            - image:
                source:
                  gcsImageUri: ${gsUri}
              features:
              - type: LABEL_DETECTION
              - type: SAFE_SEARCH_DETECTION
              - type: IMAGE_PROPERTIES
        result: imageAnalysisResponse
    - transformImageAnalysisData:
        call: http.post
        args:
          url: ${urls.VISION_DATA_TRANSFORM_URL}
          auth:
            type: OIDC
          body: ${imageAnalysisResponse.body}
        result: imageMetadata
    - checkSafety:
        switch:
          - condition: ${imageMetadata.body.safe == true}
            next: storeMetadata
        next: end
    - storeMetadata:
        call: http.request
        args:
          url: ${"https://firestore.googleapis.com/v1/projects/" + projectId + "/databases/(default)/documents/pictures/" + file + "?updateMask.fieldPaths=color&updateMask.fieldPaths=labels&updateMask.fieldPaths=created"}
          auth:
            type: OAuth2
          method: PATCH
          body:
            name: ${"projects/" + projectId + "/databases/(default)/documents/pictures/" + file}
            fields:
              color:
                stringValue: ${imageMetadata.body.color}
              created:
                timestampValue: ${imageMetadata.body.created}
              labels:
                arrayValue:
                  values: ${imageMetadata.body.labels}
        result: storeMetadataResponse

بعد تحليل الصورة، تتمثل الخطوتين التاليتين في إنشاء صورة مصغّرة للصورة وصورة مجمّعة لأحدث الصور. ويتم ذلك من خلال نشر خدمتين من خدمات تشغيل السحابة الإلكترونية وإجراء اتصالات بهما من خلال thumbnailCall وcollageCall خطوة:

76f9179323c3144.png

خطوات في YAML:

   - thumbnailCall:
        call: http.post
        args:
          url: ${urls.THUMBNAILS_URL}
          auth:
            type: OIDC
          body:
              gcsImageUri: ${gsUri}
        result: thumbnailResponse
    - collageCall:
        call: http.get
        args:
          url: ${urls.COLLAGE_URL}
          auth:
            type: OIDC
        result: collageResponse

ينتهي فرع التنفيذ هذا من خلال عرض رموز الحالة من كل خدمة في خطوة واحدة (finalizeCompleted):

    - finalizeCompleted:
        return:
          imageAnalysis: ${imageAnalysisResponse.code}
          storeMetadata: ${storeMetadataResponse.code}
          thumbnail: ${thumbnailResponse.code}
          collage: ${collageResponse.code}

الفرع الآخر للتنفيذ هو عندما يتم حذف ملف من حزمة التخزين الرئيسية، التي تحتوي على نسخ عالية الدقة من الصور. في هذا الفرع، نريد حذف الصورة المصغّرة للصورة في الحزمة التي تحتوي على صور مصغّرة وحذف بياناتها الوصفية من Firestore. ويتم إجراء ذلك من خلال استدعاءات HTTP من Workflows:

f172379274dcb3c2.png

خطوات في YAML:

    - pictureGarbageCollectionGCS:
        try:
          call: http.request
          args:
            url: ${"https://storage.googleapis.com/storage/v1/b/thumbnails-" + projectId + "/o/" + file}
            auth:
              type: OAuth2
            method: DELETE
          result: gcsDeletionResult
        except:
          as: e
          steps:
              - dummyResultInOutVar:
                  assign:
                      - gcsDeletionResult:
                          code: 200
                          body: "Workaround for empty body response"
    - pictureGarbageCollectionFirestore:
        call: http.request
        args:
          url: ${"https://firestore.googleapis.com/v1/projects/" + projectId + "/databases/(default)/documents/pictures/" + file}
          auth:
            type: OAuth2
          method: DELETE
        result: firestoreDeletionResult

وينتهي فرع الحذف بعرض النتائج / الرموز من كل خطوة:

    - deleteCompleted:
        return:
          gcsDeletion: ${gcsDeletionResult}
          firestoreDeletion: ${firestoreDeletionResult.code}

في الخطوات التالية، سننشئ جميع الاعتماديات الخارجية لسير العمل: الحزم، ودوال السحابة، وخدمات تشغيل السحابة الإلكترونية، وقاعدة بيانات Firestore.

7. إنشاء الحِزم

تحتاج إلى مجموعتَين للصور: مجموعة واحدة لحفظ الصور الأصلية عالية الدقة والأخرى لحفظ الصور المصغّرة للصور.

أنشِئ حزمة إقليمية عامة (في هذه الحالة في أوروبا) مع إذن وصول موحد للمستخدمين لتحميل الصور إليها، باستخدام أداة gsutil:

export BUCKET_PICTURES=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}
gsutil mb -l EU gs://${BUCKET_PICTURES}
gsutil uniformbucketlevelaccess set on gs://${BUCKET_PICTURES}
gsutil iam ch allUsers:objectViewer gs://${BUCKET_PICTURES}

إنشاء حزمة إقليمية أخرى للصور المصغّرة:

export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
gsutil mb -l EU gs://${BUCKET_THUMBNAILS}
gsutil uniformbucketlevelaccess set on gs://${BUCKET_THUMBNAILS}
gsutil iam ch allUsers:objectViewer gs://${BUCKET_THUMBNAILS}

يمكنك التحقّق جيدًا من إنشاء الحِزم وإتاحتها للجميع من خلال الانتقال إلى قسم Cloud Storage في Cloud Console:

15063936edd72f06.png

8. تحويل بيانات الرؤية (وظيفة السحابة)

يبدأ Workflows.yaml بخطوات init وeventTypeSwitch وeventTypeNotSupported. يتأكد هذا من توجيه الأحداث الواردة من الحِزم إلى الخطوات الصحيحة.

بالنسبة إلى حدث object.finalize، تُجري الخطوة imageAnalysisCall طلب بيانات إلى Vision API لاستخراج البيانات الوصفية للصورة التي تم إنشاؤها. يتم تنفيذ كل هذه الخطوات ضمن Workflows:

daaed43a22d2b0d3.png

بعد ذلك، نحتاج إلى تحويل البيانات التي تم إرجاعها من Vision API، قبل أن نتمكّن من حفظها في Firestore. وبشكل أكثر تحديدًا، نحتاج إلى:

  • أدرِج التصنيفات التي تم إرجاعها للصورة.
  • استرداد اللون السائد في الصورة.
  • حدد ما إذا كانت الصورة آمنة.

يتم ذلك في التعليمات البرمجية في دالة السحابة الإلكترونية، وتستدعي Workflows ببساطة هذه الدالة:

5e120e70c67779cd.png

استكشاف الرمز

تُسمى دالة السحابة الإلكترونية vision-data-transform. يمكنك التحقق من الرمز الكامل في index.js. كما ترون، الغرض الوحيد من هذه الدالة هو تحويل JSON إلى JSON، وذلك لتخزين البيانات الوصفية للصور بسهولة في Firestore.

النشر في دوال Cloud

الانتقال إلى المجلد:

cd workflows/functions/vision-data-transform/nodejs

حدد المنطقة التي تختارها:

export REGION=europe-west1
gcloud config set functions/region ${REGION}

نشر الدالة باستخدام:

export SERVICE_NAME=vision-data-transform
gcloud functions deploy ${SERVICE_NAME} \
  --source=. \
  --runtime nodejs10 \
  --entry-point=vision_data_transform \
  --trigger-http \
  --allow-unauthenticated

بعد تفعيل الدالة، ستتمكّن خطوة transformImageAnalysisData في Workflows من استدعاء هذه الدالة لتنفيذ تحويل بيانات Vision API.

9. إعداد قاعدة البيانات

في ما يلي الخطوات التالية في Workflows: التحقّق من أمان الصورة من بيانات الصور، ثم تخزين معلومات حول الصورة التي تم عرضها من خلال Vision API في قاعدة بيانات Cloud Firestore، وهي قاعدة بيانات مستند NoSQL سريعة ومدارة بالكامل وبدون خادم ومستنِدة إلى السحابة الإلكترونية:

6624c616bc7cd97f.png

يتم تنفيذ كليهما في Workflows ولكنك تحتاج إلى إنشاء قاعدة بيانات Firestore لتخزين بيانات التعريف.

أولاً، أنشئ تطبيق App Engine في المنطقة التي تريد إنشاء قاعدة بيانات Firestore فيها (أحد متطلبات Firestore):

export REGION_FIRESTORE=europe-west2
gcloud app create --region=${REGION_FIRESTORE}

بعد ذلك، أنشئ قاعدة بيانات Firestore في نفس المنطقة:

gcloud firestore databases create --region=${REGION_FIRESTORE}

سيتم إنشاء المستندات آليًا في مجموعتنا وستتضمّن 4 حقول:

  • name (سلسلة): اسم ملف الصورة التي تم تحميلها، وهو أيضًا مفتاح المستند
  • labels (مصفوفة من السلاسل): تصنيفات العناصر المعروفة بواسطة Vision API
  • color (سلسلة): رمز اللون السداسي العشري للون السائد (مثل #ab12ef)
  • CREATE (التاريخ): الطابع الزمني لوقت تخزين البيانات الوصفية لهذه الصورة
  • الصورة المصغّرة (قيمة منطقية): حقل اختياري يتم عرضه ويكون صحيحًا إذا تم إنشاء صورة مصغّرة لهذه الصورة

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

gcloud firestore indexes composite create --collection-group=pictures \
  --field-config field-path=thumbnail,order=descending \
  --field-config field-path=created,order=descending

تجدر الإشارة إلى أنّ إنشاء الفهرس قد يستغرق 10 دقائق تقريبًا.

بعد إنشاء الفهرس، يمكنك الاطّلاع عليه في Cloud Console:

43af1f5103bf423.png

ستتمكن خطوة سير العمل storeMetadata من تخزين البيانات الوصفية للصور في Firestore الآن.

10. خدمة الصور المصغّرة (تشغيل السحابة الإلكترونية)

التالي في السلسلة هو إنشاء صورة مصغرة لصورة. ويتم ذلك في رمز برمجي في خدمة تشغيل السحابة الإلكترونية وتستدعي خدمة Workflows هذه الخدمة في خطوة واحدة (thumbnailCall):

84d987647f082b53.png

استكشاف الرمز

يُطلق على خدمة التشغيل في السحابة الإلكترونية اسم thumbnails. يمكنك التحقق من الرمز الكامل في index.js.

إنشاء صورة الحاوية ونشرها

يعمل Cloud Run على تشغيل الحاويات، ولكن عليك أولاً إنشاء صورة الحاوية (تم تحديدها في Dockerfile). يمكن استخدام Google Cloud Build لإنشاء صور الحاويات، ثم استضافته في Google Container Registry.

الانتقال إلى المجلد:

cd workflows/services/thumbnails/nodejs

الإصدار:

export SERVICE_SRC=thumbnails
export SERVICE_NAME=${SERVICE_SRC}-service
gcloud builds submit \
  . \
  --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}

بعد دقيقة أو دقيقتين، من المفترض أن تنجح عملية الإنشاء وسيتم نشر الحاوية إلى Google Container Registry.

النشر إلى تشغيل السحابة الإلكترونية

اضبط بعض المتغيّرات والإعدادات المطلوبة:

export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
gcloud config set run/region ${REGION}
gcloud config set run/platform managed

انشر باستخدام الأمر التالي:

gcloud run deploy ${SERVICE_NAME} \
    --image gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME} \
    --no-allow-unauthenticated \
    --memory=1Gi \
    --update-env-vars BUCKET_THUMBNAILS=${BUCKET_THUMBNAILS}

بعد نشر الخدمة، ستتمكّن خطوة thumbnailCall في سير العمل من طلب هذه الخدمة.

11. خدمة الصور المجمَّعة (تشغيل السحابة الإلكترونية)

الخطوة التالية في السلسلة هي إنشاء صورة مجمّعة من أحدث الصور. ويتم ذلك في رمز برمجي في خدمة تشغيل السحابة الإلكترونية وتستدعي خدمة Workflows هذه الخدمة في خطوة واحدة (collageCall):

591e36149066e1ba.png

استكشاف الرمز

يُطلق على خدمة التشغيل في السحابة الإلكترونية اسم collage. يمكنك التحقق من الرمز الكامل في index.js.

إنشاء صورة الحاوية ونشرها

يعمل Cloud Run على تشغيل الحاويات، ولكن عليك أولاً إنشاء صورة الحاوية (تم تحديدها في Dockerfile). يمكن استخدام Google Cloud Build لإنشاء صور الحاويات، ثم استضافته في Google Container Registry.

الانتقال إلى المجلد:

cd services/collage/nodejs

الإصدار:

export SERVICE_SRC=collage
export SERVICE_NAME=${SERVICE_SRC}-service
gcloud builds submit \
  . \
  --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}

بعد دقيقة أو دقيقتين، من المفترض أن تنجح عملية الإنشاء وسيتم نشر الحاوية إلى Google Container Registry.

النشر إلى تشغيل السحابة الإلكترونية

اضبط بعض المتغيّرات والإعدادات المطلوبة:

export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
gcloud config set run/region ${REGION}
gcloud config set run/platform managed

النشر:

gcloud run deploy ${SERVICE_NAME} \
    --image gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME} \
    --no-allow-unauthenticated \
    --memory=1Gi \
    --update-env-vars BUCKET_THUMBNAILS=${BUCKET_THUMBNAILS}

بعد نشر الخدمة، يمكنك التحقّق من تشغيل كلتا الخدمتَين ضمن قسم "التشغيل في السحابة الإلكترونية" في Cloud Console، وستتمكّن collageCall في سير العمل من طلب هذه الخدمة:

3ae9873f4cbbf423.png

12. نشر سير العمل

نشرنا جميع الاعتماديات الخارجية لسير العمل. يمكن إكمال كل الخطوات المتبقية (finalizeCompleted، وpictureGarbageCollectionGCS، وpictureGarbageCollectionFirestore، وdeleteCompleted) من خلال منصة Workflows نفسها.

حان الوقت لنشر سير العمل!

انتقِل إلى المجلّد الذي يحتوي على ملف workflows.yaml وانشره باستخدام:

export WORKFLOW_REGION=europe-west4
export WORKFLOW_NAME=picadaily-workflows
gcloud workflows deploy ${WORKFLOW_NAME} \
  --source=workflows.yaml \
  --location=${WORKFLOW_REGION}

في بضع ثوانٍ، من المفترض أن يتم نشر Workflow ويمكنك الاطّلاع عليه في قسم Workflows في Cloud Console:

94a720149e5df9c5.png

يمكنك النقر فوق Workflow وتعديله، إذا أردت. أثناء التعديل، تحصل على تمثيل مرئي جميل لسير العمل:

55441b158f6027f3.png

يمكنك أيضًا تنفيذ سير العمل من Cloud Console يدويًا باستخدام المَعلمات الصحيحة. بدلاً من ذلك، سننفّذها تلقائيًا استجابةً لأحداث Cloud Storage في الخطوة التالية.

13. مشغِّلات سير العمل (Cloud Functions)

تم نشر سير العمل وأصبح جاهزًا. نحتاج الآن إلى تفعيل "سير العمل" عند إنشاء ملف أو حذفه في حزمة Cloud Storage. هذان الحدثان storage.object.finalize وstorage.object.delete على التوالي.

تحتوي سير العمل على واجهات برمجة تطبيقات ومكتبات عملاء لإنشاء مهام سير العمل التي يمكنك استخدامها وإدارتها وتنفيذها. في هذه الحالة، ستستخدم Workflows Execution API ومكتبة برامج Node.js تحديدًا لتشغيل "سير العمل".

سيتم تشغيل الاستماع إلى أحداث Cloud Storage في Workflows من دالة Cloud Function. بما أنّ دالة Cloud يمكنها الاستماع إلى نوع حدث واحد فقط، عليك نشر دالتَي Cloud للاستماع إلى أحداث الإنشاء والحذف:

c4d79646de729e4.png

استكشاف الرمز

تُسمى دالة السحابة الإلكترونية trigger-workflow. يمكنك التحقق من الرمز الكامل في index.js.

النشر في دوال Cloud

الانتقال إلى المجلد:

cd workflows/functions/trigger-workflow/nodejs

اضبط بعض المتغيّرات والإعدادات المطلوبة:

export BUCKET_PICTURES=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
export WORKFLOW_NAME=picadaily-workflows
export WORKFLOW_REGION=europe-west4
export COLLAGE_URL=$(gcloud run services describe collage-service --format 'value(status.url)')
export THUMBNAILS_URL=$(gcloud run services describe thumbnails-service --format 'value(status.url)')
export VISION_DATA_TRANSFORM_URL=$(gcloud functions describe vision-data-transform --format 'value(httpsTrigger.url)')
gcloud config set functions/region ${REGION}

تفعيل الدالة التي تستجيب لإنهاء الأحداث:

export SERVICE_NAME=trigger-workflow-on-finalize
gcloud functions deploy ${SERVICE_NAME} \
  --source=. \
  --runtime nodejs10 \
  --entry-point=trigger_workflow \
  --trigger-resource=${BUCKET_PICTURES} \
  --trigger-event=google.storage.object.finalize \
  --allow-unauthenticated \
  --set-env-vars GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT},WORKFLOW_REGION=${WORKFLOW_REGION},WORKFLOW_NAME=${WORKFLOW_NAME},THUMBNAILS_URL=${THUMBNAILS_URL},COLLAGE_URL=${COLLAGE_URL},VISION_DATA_TRANSFORM_URL=${VISION_DATA_TRANSFORM_URL}

نشر الدالة الثانية للاستجابة لحذف الأحداث:

export SERVICE_NAME=trigger-workflow-on-delete
gcloud functions deploy ${SERVICE_NAME} \
  --source=. \
  --runtime nodejs10 \
  --entry-point=trigger_workflow \
  --trigger-resource=${BUCKET_PICTURES} \
  --trigger-event=google.storage.object.delete \
  --allow-unauthenticated \
  --set-env-vars GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT},WORKFLOW_REGION=${WORKFLOW_REGION},WORKFLOW_NAME=${WORKFLOW_NAME},THUMBNAILS_URL=${THUMBNAILS_URL},COLLAGE_URL=${COLLAGE_URL},VISION_DATA_TRANSFORM_URL=${VISION_DATA_TRANSFORM_URL}

عند اكتمال النشر، يمكنك الاطّلاع على كلتا الوظيفتَين في Cloud Console:

7d60c8b7851f39f5.png

14. الواجهة الأمامية (App Engine)

في هذه الخطوة، يمكنك إنشاء واجهة أمامية على Google App Engine من Pic-a-daily: التمرين المعملي 4 - إنشاء واجهة أمامية للويب تسمح للمستخدمين بتحميل الصور من تطبيق الويب، وكذلك تصفح الصور التي تم تحميلها وصورها المصغرة.

223fb2281614d053.png

يمكنك معرفة المزيد من المعلومات حول App Engine وقراءة وصف الرمز في Pic-a-daily: التمرين المعملي 4 - إنشاء واجهة أمامية للويب.

استكشاف الرمز

يُطلق على تطبيق App Engine اسم frontend. يمكنك التحقق من الرمز الكامل في index.js.

النشر في App Engine

الانتقال إلى المجلد:

cd frontend

حدِّد المنطقة التي تختارها واستبدِل أيضًا GOOGLE_CLOUD_PROJECT في app.yaml برقم تعريف المشروع الفعلي:

export REGION=europe-west1
gcloud config set compute/region ${REGION}
sed -i -e "s/GOOGLE_CLOUD_PROJECT/${GOOGLE_CLOUD_PROJECT}/" app.yaml

النشر:

gcloud app deploy app.yaml -q

بعد دقيقة أو دقيقتين، سيتم إخبارك بأنّ التطبيق يعرض زيارات:

Beginning deployment of service [default]...
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 8 files to Google Cloud Storage                ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [default]...done.
Setting traffic split for service [default]...done.
Deployed service [default] to [https://GOOGLE_CLOUD_PROJECT.appspot.com]
You can stream logs from the command line by running:
  $ gcloud app logs tail -s default
To view your application in the web browser run:
  $ gcloud app browse

يمكنك أيضًا الانتقال إلى قسم App Engine في Cloud Console لمعرفة ما إذا تم نشر التطبيق واستكشاف ميزات App Engine مثل تحديد الإصدارات وتقسيم عدد الزيارات:

f4bd5f4de028bd83.png

15. اختبار سير العمل

للاختبار، انتقِل إلى عنوان URL التلقائي لـ App Engine للتطبيق (https://<YOUR_PROJECT_ID>.appspot.com/) ومن المفترض أن تظهر واجهة المستخدم الأمامية وهي قيد التشغيل.

1649ac060441099.png

حمِّل صورة. من المفترض أن يؤدي هذا إلى تشغيل سير العمل ويمكنك الاطّلاع على تنفيذ سير العمل بالحالة Active في Cloud Console:

b5a2a3d7a2bc094.png

بعد الانتهاء من تنفيذ "سير العمل"، يمكنك النقر على رقم تعريف التنفيذ والاطّلاع على النتائج من الخدمات المختلفة:

8959df5098c21548.png

يُرجى تحميل 3 صور أخرى. من المفترض أن تظهر لك أيضًا الصورة المصغّرة والصور المجمَّعة في حِزم Cloud Storage والواجهة الأمامية لـ App Engine بعد تعديلها:

d90c786ff664a5dc.png

16. إخلاء مساحة تخزين (اختياري)

إذا كنت لا تنوي الاحتفاظ بالتطبيق، يمكنك تنظيف الموارد لتوفير التكاليف ولتكون من المواطنين الجيدين بشكل عام من خلال حذف المشروع بأكمله:

gcloud projects delete ${GOOGLE_CLOUD_PROJECT} 

17. تهانينا!

لقد أنشأت إصدارًا منسقًا من التطبيق باستخدام Workflows لتنظيم الخدمات والاتصال بها.

المواضيع التي تناولناها

  • App Engine
  • Cloud Firestore
  • وظائف السحابة الإلكترونية
  • Cloud Run
  • Workflows