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

1. نظرة عامة

في المختبرات السابقة، أنشأت إصدارًا يعتمد على الأحداث من تطبيق Pic-a-daily الذي يستخدم Cloud Function يتم تشغيله من خلال Google Cloud Storage لخدمة "تحليل الصور"، وحاوية Cloud Run يتم تشغيلها من خلال GCS عبر Pub/Sub لخدمة "الصور المصغّرة"، وEventarc لتشغيل خدمة "جامع البيانات غير المرغوب فيها للصور" على Cloud Run. كانت هناك أيضًا خدمة Collage تم تشغيلها من خلال Cloud Scheduler:

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- مقدمة عن Workflows

90fcd42d556e310e.jpeg

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

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

وهو أكثر من مجرد أداة تنسيق، إذ يتضمّن الميزات المضمّنة والقابلة للضبط التالية:

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

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

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

في هذا التمرين العملي، ستربط بين خدمات Cloud Functions وCloud Run باستخدام Workflows. ستستخدم أيضًا 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 على دوال Cloud Functions التي تم إنشاؤها لسير العمل.
  • يحتوي services على خدمات Cloud Run المعدَّلة لسير العمل.
  • workflows.yaml هو ملف تعريف سير العمل.

6. استكشاف ملف YAML الخاص بـ Workflows

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

في بداية سير العمل، يتم تمرير بعض المَعلمات. سيتم تمريرها من خلال وظيفتَين في Cloud Functions تؤديان إلى تشغيل سير العمل. سنتناول هذه الدوال لاحقًا، ولكن إليك طريقة بدء "مهام سير العمل":

d44a5e18aa9d4660.png

في YAML، يمكنك ملاحظة أنّه يتم تعيين هذه المَعلمات إلى متغيرات في الخطوة init، مثل أسماء الملفات والحِزم التي تؤدي إلى تشغيل الحدث، وعناوين URL لبعض خدمات Cloud Functions وCloud Run التي ستستدعيها 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}

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

يُرجى العلم أنّه يتم تنفيذ كل شيء في "مهام سير العمل" باستثناء "وظائف Vision Transform Cloud" (التي سننشرها لاحقًا):

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

بعد تحليل الصورة، تتمثّل الخطوتان التاليتان في إنشاء صورة مصغّرة للصورة ومجموعة من أحدث الصور. يتم ذلك من خلال نشر خدمتَين من Cloud Run وإجراء طلبات إليهما من الخطوتَين 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}

في الخطوات التالية، سننشئ جميع التبعيات الخارجية لسير العمل: الحِزم وCloud Functions وخدمات Cloud Run وقاعدة بيانات 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. تحويل بيانات Vision (دالة Cloud)

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

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

daaed43a22d2b0d3.png

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

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

يتم ذلك في الرمز البرمجي في Cloud Function، وتستدعي Workflows هذه الدالة ببساطة:

5e120e70c67779cd.png

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

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

النشر على Cloud Functions

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

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- إعداد قاعدة البيانات

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

6624c616bc7cd97f.png

يتم تنفيذ كلتا العمليتين في "مهام سير العمل"، ولكن عليك إنشاء قاعدة بيانات 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)
  • created (التاريخ): الطابع الزمني لوقت تخزين البيانات الوصفية لهذه الصورة
  • thumbnail (قيمة منطقية): حقل اختياري سيظهر وتكون قيمته صحيحة إذا تم إنشاء صورة مصغّرة لهذه الصورة

بما أنّنا سنبحث في 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

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

10. خدمة الصور المصغّرة (Cloud Run)

الخطوة التالية في السلسلة هي إنشاء صورة مصغّرة. يتم ذلك في الرمز البرمجي في إحدى خدمات Cloud Run، وتطلب Workflows هذه الخدمة في الخطوة thumbnailCall:

84d987647f082b53.png

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

اسم خدمة Cloud Run هو 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.

النشر على Cloud Run

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

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. خدمة الصور المجمّعة (Cloud Run)

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

591e36149066e1ba.png

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

اسم خدمة Cloud Run هو 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.

النشر على Cloud Run

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

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 Run في Cloud Console، وستتمكّن الخطوة collageCall في Workflows من استدعاء هذه الخدمة:

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}

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

94a720149e5df9c5.png

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

55441b158f6027f3.png

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

13. مشغّلات Workflows (دوال Cloud)

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

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

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

c4d79646de729e4.png

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

يُطلق على دالة Cloud اسم trigger-workflow. يمكنك الاطّلاع على الرمز الكامل في index.js.

النشر على Cloud Functions

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

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: Lab 4—Create a web frontend تتيح للمستخدمين تحميل الصور من تطبيق الويب، بالإضافة إلى تصفّح الصور المحمَّلة والصور المصغّرة الخاصة بها.

223fb2281614d053.png

يمكنك الاطّلاع على مزيد من المعلومات عن App Engine وقراءة وصف الرمز البرمجي في Pic-a-daily: Lab 4—Create a web frontend.

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

اسم تطبيق 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. تهانينا!

لقد أنشأت إصدارًا منسَّقًا من التطبيق باستخدام "عمليات سير العمل" لتنسيق الخدمات واستدعائها.

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

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