1. סקירה כללית
במעבדות הקודמות יצרתם גרסה מבוססת-אירועים של אפליקציית Pic-a-daily, שהשתמשה בפונקציית Cloud Functions שהופעלה על ידי Google Cloud Storage עבור שירות ניתוח התמונות, בקונטיינר Cloud Run שהופעל על ידי GCS באמצעות Pub/Sub עבור שירות התמונות הממוזערות, וב-Eventarc כדי להפעיל את שירות ניקוי התמונות ב-Cloud Run. היה גם שירות קולאז' שהופעל על ידי Cloud Scheduler:

בשיעור ה-Lab הזה תיצרו גרסה מתואמת של האפליקציה. במקום שסוגים שונים של אירועים יזרמו דרך המערכת, תשתמשו ב-Workflows כדי לתאם את השירותים ולקרוא להם באופן הבא:

מה תלמדו
- App Engine
- Cloud Firestore
- Cloud Functions
- Cloud Run
- תהליכי עבודה
2. הגדרה ודרישות
הגדרת סביבה בקצב אישי
- נכנסים אל Cloud Console ויוצרים פרויקט חדש או משתמשים בפרויקט קיים. (אם עדיין אין לכם חשבון Gmail או Google Workspace, אתם צריכים ליצור חשבון).



חשוב לזכור את מזהה הפרויקט, שהוא שם ייחודי בכל הפרויקטים ב-Google Cloud (השם שלמעלה כבר תפוס ולא יתאים לכם, מצטערים!). בהמשך ה-codelab הזה נתייחס אליו כאל PROJECT_ID.
- לאחר מכן, תצטרכו להפעיל את החיוב ב-Cloud Console כדי להשתמש במשאבים של Google Cloud.
העלות של התרגול הזה לא אמורה להיות גבוהה, ואולי אפילו לא תצטרכו לשלם בכלל. חשוב לפעול לפי ההוראות בקטע 'ניקוי' כדי להשבית את המשאבים, וכך לא תחויבו אחרי שתסיימו את המדריך הזה. משתמשים חדשים ב-Google Cloud זכאים לתוכנית תקופת ניסיון בחינם בשווי 300$.
מפעילים את Cloud Shell
אפשר להפעיל את Google Cloud מרחוק מהמחשב הנייד, אבל ב-codelab הזה תשתמשו ב-Google Cloud Shell, סביבת שורת פקודה שפועלת בענן.
ב-GCP Console, לוחצים על סמל Cloud Shell בסרגל הכלים שבפינה הימנית העליונה:

יחלפו כמה רגעים עד שההקצאה והחיבור לסביבת העבודה יושלמו. בסיום התהליך, אמור להופיע משהו כזה:

המכונה הווירטואלית הזו כוללת את כל הכלים שדרושים למפתחים. יש בה ספריית בית בנפח מתמיד של 5GB והיא פועלת ב-Google Cloud, מה שמשפר מאוד את הביצועים והאימות ברשת. אפשר לבצע את כל העבודה ב-Lab הזה רק באמצעות דפדפן.
3. מבוא ל-Workflows

אתם יכולים להשתמש ב-Workflows כדי ליצור תהליכי עבודה ללא שרת שמקשרים בין סדרה של משימות ללא שרת בסדר שאתם מגדירים. אתם יכולים לשלב בין היכולות של ממשקי ה-API של Google Cloud, מוצרים בלי שרת (serverless) כמו Cloud Functions ו-Cloud Run, וקריאות לממשקי API חיצוניים כדי ליצור אפליקציות גמישות בלי שרת (serverless).
כמו בכל כלי לתזמור, Workflows מאפשר להגדיר את זרימת הלוגיקה העסקית בשפת הגדרת תהליכי עבודה מבוססת YAML/JSON, ומספק Workflows Execution API וממשק משתמש של Workflows להפעלת התהליכים האלה.
הוא לא רק כלי לניהול תהליכים, אלא גם כולל את התכונות המובנות והניתנות להגדרה הבאות:
- ניסיון חוזר גמיש וטיפול בשגיאות בין השלבים, כדי להבטיח ביצוע אמין של השלבים.
- ניתוח JSON והעברת משתנים בין שלבים כדי להימנע מקוד דבק.
- נוסחאות של ביטויים להחלטות מאפשרות ביצוע מותנה של שלבים.
- תהליכי עבודה משניים (subworkflows) ליצירת תהליכי עבודה מודולריים ורב-פעמיים.
- התמיכה בשירותים חיצוניים מאפשרת תזמור של שירותים מחוץ ל-Google Cloud.
- תמיכה באימות לשירותי Google Cloud ולשירותים חיצוניים, לביצוע מאובטח של שלבים.
- מחברים לשירותי Google Cloud כמו Pub/Sub, Firestore, Tasks, Secret Manager לשילוב קל יותר.
בנוסף, Workflows הוא מוצר מנוהל באופן מלא ללא שרת (serverless). אין צורך להגדיר או להרחיב שרתים, ומשלמים רק על מה שמשתמשים בו.
4. הפעלת ממשקי ה-API
בשיעור ה-Lab הזה תלמדו איך לקשר בין שירותי 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
זה מבנה התיקיות שרלוונטי לשיעור ה-Lab הזה:
frontend | workflows | ├── functions ├── |── trigger-workflow ├── |── vision-data-transform ├── services ├── |── collage ├── |── thumbnails ├── workflows.yaml
אלה התיקיות הרלוונטיות:
-
frontendמכיל את הקצה הקדמי של App Engine שנעשה בו שימוש חוזר משיעור Lab 4. - השדה
functionsמכיל את פונקציות Cloud Functions שנוצרו עבור תהליך העבודה. -
servicesמכיל את שירותי Cloud Run שהשתנו בשביל Workflow. -
workflows.yamlהוא קובץ הגדרת תהליך העבודה.
6. עיון בקובץ ה-YAML של תהליכי העבודה
הקובץ workflows.yaml מגדיר את תהליך העבודה בסדרת שלבים. כדאי לעבור על זה כדי להבין טוב יותר.
בתחילת תהליך העבודה יש כמה פרמטרים שמועברים. הם יועברו על ידי שתי פונקציות Cloud Functions שמפעילות את Workflows. נחזור לפונקציות האלה בהמשך, אבל כך מתחיל תהליך העבודה:

ב-YAML, אפשר לראות שהפרמטרים האלה מוקצים למשתנים בשלב init, כמו שמות הקבצים והמאגרי מידע שמופעלים על ידי האירוע, וכתובות URL של שירותי Cloud Functions ו-Cloud Run מסוימים שהזרימות יפעילו:
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}
לאחר מכן, כלי זרימות העבודה בודק את סוג האירוע. יש 2 סוגי אירועים נתמכים: object.finalize (מופעל כשקובץ נשמר בדלי של אחסון בענן) ו-object.delete (מופעל כשקובץ נמחק). כל דבר אחר יגרום לחריגה של אירוע שלא נתמך.

הנה השלב בהגדרת תהליך העבודה ב-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
שימו לב שתהליכי עבודה תומכים בהצהרות switch ובטיפול בחריגים, עם הוראת ה-switch והתנאים השונים שלה, והוראת ה-raise להעלאת שגיאה כשהאירוע לא מזוהה.
עכשיו נבדוק את imageAnalysisCall. זו סדרה של קריאות מ-Workflows לקריאה ל-Vision API כדי לנתח את התמונה, לשנות את נתוני התגובה של Vision API כדי למיין את התוויות של הדברים שזוהו בתמונה, לבחור את הצבעים הדומיננטיים, לבדוק אם התמונה בטוחה להצגה ואז לשמור את המטא-נתונים ב-Cloud Firestore.
שימו לב: כל הפעולות מתבצעות ב-Workflows, למעט הפונקציות ב-Cloud Functions של Vision Transform (שנפרוס בהמשך):

כך השלבים נראים ב-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:

שלבים ב-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:

שלבים ב-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}
בשלבים הבאים ניצור את כל התלויות החיצוניות של Workflows: דליים, Cloud Functions, שירותי Cloud Run ומסד נתונים של Firestore.
7. יצירת הקטגוריות
צריך 2 מאגרי תמונות: אחד לשמירת תמונות מקוריות ברזולוציה גבוהה ואחד לשמירת תמונות ממוזערות.
כדי ליצור קטגוריה ציבורית אזורית (במקרה הזה באירופה) עם גישה אחידה למשתמשים להעלאת תמונות, משתמשים בכלי 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:

8. Vision Data Transform (Cloud Function)
הקובץ Workflows.yaml מתחיל בשלבים init, eventTypeSwitch ו-eventTypeNotSupported. הם מוודאים שהאירועים שמגיעים ממאגרי מידע מנותבים לשלבים הנכונים.
בשלב object.finalize של האירוע, imageAnalysisCall מתבצעת קריאה ל-Vision API כדי לחלץ מטא-נתונים של התמונה שנוצרה. כל השלבים האלה מתבצעים ב-Workflows:

לאחר מכן, נצטרך לשנות את הנתונים שמוחזרים מ-Vision API לפני שנוכל לשמור אותם ב-Firestore. באופן ספציפי יותר, אנחנו צריכים:
- רשימת התוויות שמוחזרות עבור התמונה.
- שליפת הצבע הדומיננטי של התמונה.
- בודקים אם התמונה בטוחה.
הפעולה הזו מתבצעת בקוד בפונקציה של Cloud Functions, ו-Workflows פשוט קורא לפונקציה הזו:

עיון בקוד
הפונקציה של Cloud Functions נקראת 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, שהוא מסד נתונים מהיר, מנוהל באופן מלא, מבוסס-ענן, בלי שרת (serverless) ולא יחסי (NoSQL):

שני השלבים האלה מתבצעים ב-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)
- created (תאריך): חותמת הזמן של מועד שמירת המטא-נתונים של התמונה
- thumbnail (בוליאני): שדה אופציונלי שיופיע ויקבל את הערך true אם נוצרה תמונה ממוזערת לתמונה הזו
כדי שנוכל לחפש ב-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:

מעכשיו אפשר לאחסן את המטא-נתונים של התמונה ב-Firestore בשלב storeMetadata של תהליכי העבודה.
10. שירות התמונות הממוזערות (Cloud Run)
השלב הבא בשרשרת הוא ליצור תמונה ממוזערת של תמונה. הפעולה הזו מתבצעת בקוד בשירות Cloud Run, ו-Workflows קורא לשירות הזה בשלב thumbnailCall:

עיון בקוד
שירות Cloud Run נקרא thumbnails. אפשר לבדוק את הקוד המלא שלו בקובץ index.js.
יצירה ופרסום של קובץ אימג' של קונטיינר
Cloud Run מריץ קונטיינרים, אבל קודם צריך ליצור את קובץ האימג' של הקונטיינר (מוגדר ב-Dockerfile). אפשר להשתמש ב-Google Cloud Build כדי ליצור קובצי אימג' של קונטיינרים ולאחר מכן לארח אותם ב-Google Container Registry.
עוברים לתיקייה:
cd workflows/services/thumbnails/nodejs
גרסת Build:
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}
אחרי פריסת השירות, השלב Workflows thumbnailCall יוכל להפעיל את השירות הזה.
11. שירות קולאז' (Cloud Run)
השלב הבא בשרשרת הוא ליצור קולאז' מהתמונות האחרונות. הפעולה הזו מתבצעת בקוד בשירות Cloud Run, ו-Workflows קורא לשירות הזה בשלב collageCall:

עיון בקוד
שירות Cloud Run נקרא collage. אפשר לבדוק את הקוד המלא שלו בקובץ index.js.
יצירה ופרסום של קובץ אימג' של קונטיינר
Cloud Run מריץ קונטיינרים, אבל קודם צריך ליצור את קובץ האימג' של הקונטיינר (מוגדר ב-Dockerfile). אפשר להשתמש ב-Google Cloud Build כדי ליצור קובצי אימג' של קונטיינרים ולאחר מכן לארח אותם ב-Google Container Registry.
עוברים לתיקייה:
cd services/collage/nodejs
גרסת Build:
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 יוכל לקרוא לשירות הזה:

12. פריסת תהליכי עבודה
פרסנו את כל התלויות החיצוניות של Workflows. את כל השלבים הנותרים (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:

אם רוצים, אפשר ללחוץ על תהליך העבודה ולערוך אותו. במהלך העריכה, מוצגת המחשה ויזואלית של תהליך העבודה:

אפשר גם להריץ את זרימת העבודה באופן ידני מ-Cloud Console עם הפרמטרים הנכונים. במקום זאת, נבצע אותה באופן אוטומטי בתגובה לאירועים ב-Cloud Storage בשלב הבא.
13. טריגרים של תהליכי עבודה (Cloud Functions)
תהליך העבודה נפרס ומוכן. עכשיו צריך להפעיל את Workflows כשקובץ נוצר או נמחק בקטגוריה של Cloud Storage. אלה אירועים מסוג storage.object.finalize ו-storage.object.delete, בהתאמה.
ל-Workflows יש ממשקי API וספריות לקוח שבהם אפשר להשתמש כדי ליצור, לנהל ולהפעיל תהליכי עבודה. במקרה הזה, תשתמשו ב-Workflows Execution API, ובאופן ספציפי בספריית הלקוח שלו ל-Node.js, כדי להפעיל את זרימת העבודה.
תפעילו את Workflows מ-Cloud Functions, שמאזין לאירועים ב-Cloud Storage. מכיוון שפונקציה ב-Cloud Functions יכולה להאזין רק לסוג אחד של אירוע, תצטרכו לפרוס שתי פונקציות ב-Cloud Functions כדי להאזין לאירועי יצירה ומחיקה:

עיון בקוד
הפונקציה של Cloud Functions נקראת 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:

14. קצה קדמי (App Engine)
בשלב הזה, יוצרים חזית עורפית לאתר ב-Google App Engine מתוך Pic-a-daily: Lab 4—Create a web frontend, שתאפשר למשתמשים להעלות תמונות מאפליקציית האינטרנט, וגם לעיין בתמונות שהועלו ובתמונות הממוזערות שלהן.

מידע נוסף על 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 כמו ניהול גרסאות ופיצול תנועה:

15. בדיקת תהליכי העבודה
כדי לבדוק, עוברים לכתובת ה-URL שמוגדרת כברירת מחדל לאפליקציה ב-App Engine (https://<YOUR_PROJECT_ID>.appspot.com/) וצריך לראות את ממשק המשתמש של הקצה הקדמי פועל.

מעלים תמונה. הפעולה הזו אמורה להפעיל את Workflows, ואפשר לראות את ההפעלה של Workflow במצב Active ב-Cloud Console:

אחרי שהתהליך ב-Workflows מסתיים, אפשר ללחוץ על מזהה ההפעלה ולראות את הפלט משירותים שונים:

מעלים עוד 3 תמונות. בנוסף, התמונות הממוזערות והקולאז' של התמונות בקטגוריות Cloud Storage ובקצה הקדמי של App Engine אמורים להתעדכן:

16. ניקוי (אופציונלי)
אם אתם לא מתכוונים להשאיר את האפליקציה, אתם יכולים למחוק את הפרויקט כולו כדי לחסוך בעלויות ולשמור על סביבת ענן נקייה:
gcloud projects delete ${GOOGLE_CLOUD_PROJECT}
17. מעולה!
יצרתם גרסה מתוזמרת של האפליקציה באמצעות Workflows כדי לתזמר שירותים ולהפעיל אותם.
מה נכלל
- App Engine
- Cloud Firestore
- Cloud Functions
- Cloud Run
- תהליכי עבודה