1. Tổng quan
Trong các lớp học lập trình trước, bạn đã tạo một phiên bản dựa trên sự kiện của ứng dụng Pic-a-daily. Phiên bản này sử dụng một Cloud Function được kích hoạt bằng Google Cloud Storage cho dịch vụ Phân tích hình ảnh, một vùng chứa Cloud Run được kích hoạt bằng GCS thông qua Pub/Sub cho dịch vụ Hình thu nhỏ và Eventarc để kích hoạt dịch vụ Thu gom hình ảnh không dùng đến trên Cloud Run. Ngoài ra còn có một dịch vụ Collage do Cloud Scheduler kích hoạt:

Trong lớp học này, bạn sẽ tạo một phiên bản phối hợp của ứng dụng. Thay vì các loại sự kiện khác nhau truyền qua hệ thống, bạn sẽ sử dụng quy trình công việc để điều phối và gọi các dịch vụ như sau:

Kiến thức bạn sẽ học được
- App Engine
- Cloud Firestore
- Cloud Functions
- Cloud Run
- Quy trình công việc
2. Thiết lập và yêu cầu
Thiết lập môi trường theo tốc độ của riêng bạn
- Đăng nhập vào Cloud Console rồi tạo một dự án mới hoặc sử dụng lại một dự án hiện có. (Nếu chưa có tài khoản Gmail hoặc Google Workspace, bạn phải tạo một tài khoản.)



Hãy nhớ mã dự án, một tên duy nhất trên tất cả các dự án trên Google Cloud (tên ở trên đã được sử dụng và sẽ không hoạt động đối với bạn, xin lỗi!). Sau này trong lớp học lập trình này, chúng ta sẽ gọi nó là PROJECT_ID.
- Tiếp theo, bạn cần bật tính năng thanh toán trong Cloud Console để sử dụng các tài nguyên của Google Cloud.
Việc thực hiện lớp học lập trình này sẽ không tốn nhiều chi phí, nếu có. Hãy nhớ làm theo mọi hướng dẫn trong phần "Dọn dẹp" để biết cách tắt các tài nguyên nhằm tránh bị tính phí ngoài phạm vi hướng dẫn này. Người dùng mới của Google Cloud đủ điều kiện tham gia chương trình Dùng thử miễn phí trị giá 300 USD.
Khởi động Cloud Shell
Mặc dù có thể vận hành Google Cloud từ xa trên máy tính xách tay, nhưng trong lớp học lập trình này, bạn sẽ sử dụng Google Cloud Shell, một môi trường dòng lệnh chạy trên Cloud.
Trên Bảng điều khiển GCP, hãy nhấp vào biểu tượng Cloud Shell trên thanh công cụ ở trên cùng bên phải:

Quá trình này chỉ mất vài phút để cung cấp và kết nối với môi trường. Khi quá trình này kết thúc, bạn sẽ thấy như sau:

Máy ảo này được trang bị tất cả các công cụ phát triển mà bạn cần. Nó cung cấp một thư mục chính có dung lượng 5 GB và chạy trên Google Cloud, giúp tăng cường đáng kể hiệu suất mạng và hoạt động xác thực. Bạn chỉ cần một trình duyệt là có thể thực hiện mọi thao tác trong phòng thí nghiệm này.
3. Giới thiệu về Workflows

Bạn có thể sử dụng Quy trình công việc để tạo quy trình công việc không máy chủ, liên kết một loạt các tác vụ không máy chủ với nhau theo thứ tự mà bạn xác định. Bạn có thể kết hợp sức mạnh của các API của Google Cloud, các sản phẩm không máy chủ như Cloud Functions và Cloud Run, cũng như các lệnh gọi đến các API bên ngoài để tạo các ứng dụng không máy chủ linh hoạt.
Như bạn có thể mong đợi ở một trình điều phối, Workflows cho phép bạn xác định quy trình logic nghiệp vụ của mình bằng ngôn ngữ định nghĩa quy trình công việc dựa trên YAML/JSON và cung cấp Workflows Execution API và giao diện người dùng Workflows để kích hoạt các quy trình đó.
Đây không chỉ là một trình điều phối đơn thuần mà còn có các tính năng tích hợp sẵn và có thể định cấu hình sau đây:
- Khả năng thử lại linh hoạt và xử lý lỗi giữa các bước để thực thi các bước một cách đáng tin cậy.
- Phân tích cú pháp JSON và truyền biến giữa các bước để tránh mã kết dính.
- Công thức biểu thức cho các quyết định cho phép thực thi các bước có điều kiện.
- Quy trình công việc phụ cho các quy trình công việc theo mô-đun và có thể sử dụng lại.
- Tính năng hỗ trợ cho các dịch vụ bên ngoài cho phép điều phối các dịch vụ ngoài Google Cloud.
- Hỗ trợ xác thực cho Google Cloud và các dịch vụ bên ngoài để thực thi các bước bảo mật.
- Trình kết nối với các dịch vụ của Google Cloud như Pub/Sub, Firestore, Tasks, Secret Manager để tích hợp dễ dàng hơn.
Chưa kể, Workflows là một sản phẩm không máy chủ được quản lý toàn diện. Không cần định cấu hình hoặc mở rộng quy mô máy chủ và bạn chỉ phải trả phí cho những gì bạn sử dụng.
4. Bật API
Trong phòng thí nghiệm này, bạn sẽ kết nối các dịch vụ Cloud Functions và Cloud Run với Workflows. Bạn cũng sẽ sử dụng App Engine, Cloud Build, Vision API và các dịch vụ khác.
Trong Cloud Shell, hãy đảm bảo bạn đã bật tất cả các dịch vụ cần thiết:
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 \
Sau một thời gian, bạn sẽ thấy thao tác hoàn tất thành công:
Operation "operations/acf.5c5ef4f6-f734-455d-b2f0-ee70b5a17322" finished successfully.
5. Lấy mã
Lấy mã (nếu bạn chưa lấy trong các lớp học lập trình trước):
git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop
Bạn sẽ có cấu trúc thư mục sau đây có liên quan đến lớp học này:
frontend | workflows | ├── functions ├── |── trigger-workflow ├── |── vision-data-transform ├── services ├── |── collage ├── |── thumbnails ├── workflows.yaml
Sau đây là các thư mục có liên quan:
frontendchứa giao diện người dùng App Engine mà chúng ta sẽ dùng lại từ Lớp học lập trình 4.functionschứa các Cloud Functions được tạo cho Quy trình làm việc.serviceschứa các dịch vụ Cloud Run được sửa đổi cho Quy trình công việc.workflows.yamllà tệp định nghĩa Quy trình công việc.
6. Khám phá tệp YAML của quy trình công việc
Tệp workflows.yaml xác định quy trình dưới dạng một chuỗi các bước. Hãy cùng xem xét để hiểu rõ hơn.
Khi bắt đầu quy trình công việc, có một số tham số được truyền vào. Hai Cloud Functions sẽ truyền các tham số này để kích hoạt Workflows. Chúng ta sẽ tìm hiểu các hàm này sau, nhưng đây là cách Workflows bắt đầu:

Trong YAML, bạn có thể thấy rằng các tham số này được chỉ định cho các biến trong bước init, chẳng hạn như tên tệp và tên nhóm kích hoạt sự kiện, cũng như URL của một số dịch vụ Cloud Functions và Cloud Run mà Workflows sẽ gọi:
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}
Tiếp theo, quy trình công việc sẽ kiểm tra loại sự kiện. Có 2 loại sự kiện được hỗ trợ: object.finalize (phát ra khi một tệp được lưu trong bộ nhớ trên đám mây) và object.delete (phát ra khi một tệp bị xoá). Mọi thứ khác sẽ làm phát sinh một ngoại lệ sự kiện không được hỗ trợ.

Đây là bước trong định nghĩa quy trình làm việc YAML, nơi chúng ta kiểm tra loại sự kiện lưu trữ tệp:
- 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
Lưu ý cách Workflows hỗ trợ câu lệnh chuyển đổi và xử lý ngoại lệ, với chỉ dẫn chuyển đổi và nhiều điều kiện, cũng như chỉ dẫn tăng để tăng lỗi khi sự kiện không được nhận dạng.
Tiếp theo, hãy cùng xem xét imageAnalysisCall. Đây là một loạt lệnh gọi từ Workflows để gọi Vision API nhằm phân tích hình ảnh, chuyển đổi dữ liệu phản hồi của Vision API để sắp xếp nhãn của những thứ được nhận dạng trong ảnh, chọn màu chủ đạo, kiểm tra xem hình ảnh có an toàn để hiển thị hay không, sau đó lưu siêu dữ liệu vào Cloud Firestore.
Xin lưu ý rằng mọi thao tác đều được thực hiện trong Workflows, ngoại trừ Cloud Functions Vision Transform (chúng ta sẽ triển khai sau):

Đây là cách các bước xuất hiện trong 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
Sau khi phân tích hình ảnh, hai bước tiếp theo là tạo hình thu nhỏ của hình ảnh và ảnh ghép gồm những hình ảnh gần đây nhất. Việc này được thực hiện bằng cách triển khai 2 dịch vụ Cloud Run và gọi các dịch vụ đó từ các bước thumbnailCall và collageCall:

Các bước trong 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
Nhánh thực thi này kết thúc bằng cách trả về mã trạng thái từ mỗi dịch vụ trong bước finalizeCompleted:
- finalizeCompleted:
return:
imageAnalysis: ${imageAnalysisResponse.code}
storeMetadata: ${storeMetadataResponse.code}
thumbnail: ${thumbnailResponse.code}
collage: ${collageResponse.code}
Nhánh thực thi còn lại là khi một tệp bị xoá khỏi vùng lưu trữ chính, chứa các phiên bản có độ phân giải cao của hình ảnh. Trong nhánh này, chúng ta muốn xoá hình thu nhỏ của hình ảnh trong vùng chứa hình thu nhỏ và xoá siêu dữ liệu của hình ảnh đó khỏi Firestore. Cả hai thao tác này đều được thực hiện bằng các lệnh gọi HTTP từ Workflows:

Các bước trong 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
Nhánh xoá kết thúc bằng cách trả về kết quả / mã từ mỗi bước:
- deleteCompleted:
return:
gcsDeletion: ${gcsDeletionResult}
firestoreDeletion: ${firestoreDeletionResult.code}
Trong các bước sau, chúng ta sẽ tạo tất cả các phần phụ thuộc bên ngoài của quy trình công việc: bộ chứa, Cloud Functions, dịch vụ Cloud Run và cơ sở dữ liệu Firestore.
7. Tạo các nhóm
Bạn cần 2 vùng lưu trữ cho hình ảnh: 1 để lưu hình ảnh gốc có độ phân giải cao và 1 để lưu hình thu nhỏ của hình ảnh.
Tạo một vùng lưu trữ công khai (trong trường hợp này là ở Châu Âu) có quyền truy cập đồng nhất để người dùng tải ảnh lên bằng công cụ 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}
Tạo một bucket công khai khác theo khu vực cho hình thu nhỏ:
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}
Bạn có thể kiểm tra kỹ để đảm bảo các vùng chứa được tạo và ở chế độ công khai bằng cách truy cập vào phần Cloud Storage của Cloud Console:

8. Chuyển đổi dữ liệu hình ảnh (Cloud Function)
Workflows.yaml bắt đầu bằng các bước init, eventTypeSwitch, eventTypeNotSupported. Những điều kiện này đảm bảo các sự kiện đến từ các nhóm được định tuyến đến đúng bước.
Đối với sự kiện object.finalize, bước imageAnalysisCall sẽ gọi Vision API để trích xuất siêu dữ liệu của hình ảnh đã tạo. Tất cả các bước này đều được thực hiện trong Workflows:

Tiếp theo, chúng ta cần chuyển đổi dữ liệu do Vision API trả về trước khi có thể lưu dữ liệu đó vào Firestore. Cụ thể hơn, chúng ta cần:
- Liệt kê các nhãn được trả về cho hình ảnh.
- Truy xuất màu chủ đạo của hình ảnh.
- Xác định xem bức ảnh đó có an toàn hay không.
Việc này được thực hiện trong mã trong một Cloud Functions và Workflows chỉ cần gọi hàm này:

Khám phá mã
Cloud Function này có tên là vision-data-transform. Bạn có thể kiểm tra toàn bộ mã của nó trong index.js. Như bạn thấy, mục đích duy nhất của hàm này là chuyển đổi JSON sang JSON, để lưu trữ siêu dữ liệu hình ảnh một cách thuận tiện trong Firestore.
Triển khai lên Cloud Functions
Chuyển đến thư mục:
cd workflows/functions/vision-data-transform/nodejs
Đặt khu vực bạn muốn:
export REGION=europe-west1
gcloud config set functions/region ${REGION}
Triển khai hàm bằng:
export SERVICE_NAME=vision-data-transform
gcloud functions deploy ${SERVICE_NAME} \
--source=. \
--runtime nodejs10 \
--entry-point=vision_data_transform \
--trigger-http \
--allow-unauthenticated
Sau khi hàm được triển khai, bước transformImageAnalysisData của quy trình công việc sẽ có thể gọi hàm này để thực hiện quá trình chuyển đổi dữ liệu Vision API.
9. Chuẩn bị cơ sở dữ liệu
Tiếp theo trong quy trình là kiểm tra độ an toàn của hình ảnh từ dữ liệu hình ảnh, sau đó lưu trữ thông tin về hình ảnh do Vision API trả về vào cơ sở dữ liệu Cloud Firestore, một cơ sở dữ liệu tài liệu NoSQL nhanh, được quản lý toàn diện, không máy chủ và trên đám mây:

Cả hai thao tác này đều được thực hiện trong Workflows nhưng bạn cần tạo cơ sở dữ liệu Firestore để bộ nhớ siêu dữ liệu hoạt động.
Trước tiên, hãy tạo một ứng dụng App Engine ở khu vực mà bạn muốn có cơ sở dữ liệu Firestore (một yêu cầu đối với Firestore):
export REGION_FIRESTORE=europe-west2
gcloud app create --region=${REGION_FIRESTORE}
Tiếp theo, hãy tạo cơ sở dữ liệu Firestore ở cùng khu vực:
gcloud firestore databases create --region=${REGION_FIRESTORE}
Các tài liệu sẽ được tạo theo lập trình trong bộ sưu tập của chúng tôi và sẽ chứa 4 trường:
- name (chuỗi): tên tệp của hình ảnh được tải lên, cũng là khoá của tài liệu
- labels (mảng chuỗi): nhãn của các mục được nhận dạng bằng Vision API
- color (chuỗi): mã màu thập lục phân của màu chủ đạo (ví dụ: #ab12ef)
- created (ngày): dấu thời gian cho biết thời điểm siêu dữ liệu của hình ảnh này được lưu trữ
- thumbnail (boolean): một trường không bắt buộc sẽ xuất hiện và có giá trị true nếu hình thu nhỏ đã được tạo cho bức ảnh này
Vì chúng ta sẽ tìm kiếm trong Firestore để tìm những bức ảnh có hình thu nhỏ và sắp xếp theo ngày tạo, nên chúng ta cần tạo một chỉ mục tìm kiếm. Bạn có thể tạo chỉ mục bằng lệnh sau:
gcloud firestore indexes composite create --collection-group=pictures \ --field-config field-path=thumbnail,order=descending \ --field-config field-path=created,order=descending
Xin lưu ý rằng quá trình tạo chỉ mục có thể mất khoảng 10 phút.
Sau khi tạo chỉ mục, bạn có thể thấy chỉ mục đó trong Cloud Console:

Giờ đây, bước storeMetadata trong quy trình công việc có thể lưu trữ siêu dữ liệu hình ảnh vào Firestore.
10. Dịch vụ hình thu nhỏ (Cloud Run)
Bước tiếp theo trong chuỗi là tạo hình thu nhỏ của một hình ảnh. Việc này được thực hiện trong mã của một dịch vụ Cloud Run và Workflows gọi dịch vụ này ở bước thumbnailCall:

Khám phá mã
Dịch vụ Cloud Run có tên là thumbnails. Bạn có thể kiểm tra toàn bộ mã của nó trong index.js.
Tạo và xuất bản hình ảnh vùng chứa
Cloud Run chạy các vùng chứa nhưng trước tiên bạn cần tạo hình ảnh vùng chứa (được xác định trong Dockerfile). Bạn có thể dùng Google Cloud Build để tạo hình ảnh vùng chứa rồi lưu trữ vào Google Container Registry.
Chuyển đến thư mục:
cd workflows/services/thumbnails/nodejs
Phiên bản:
export SERVICE_SRC=thumbnails
export SERVICE_NAME=${SERVICE_SRC}-service
gcloud builds submit \
. \
--tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}
Sau một hoặc hai phút, bản dựng sẽ thành công và vùng chứa sẽ được triển khai vào Google Container Registry.
Triển khai lên Cloud Run
Đặt một số biến và cấu hình cần thiết:
export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
gcloud config set run/region ${REGION}
gcloud config set run/platform managed
Triển khai bằng lệnh sau:
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}
Sau khi dịch vụ được triển khai, bước Quy trình công việc thumbnailCall sẽ có thể gọi dịch vụ này.
11. Dịch vụ ảnh ghép (Cloud Run)
Bước tiếp theo trong chuỗi là tạo ảnh ghép từ những hình ảnh gần đây nhất. Việc này được thực hiện trong mã của một dịch vụ Cloud Run và Workflows gọi dịch vụ này ở bước collageCall:

Khám phá mã
Dịch vụ Cloud Run có tên là collage. Bạn có thể kiểm tra toàn bộ mã của nó trong index.js.
Tạo và xuất bản hình ảnh vùng chứa
Cloud Run chạy các vùng chứa nhưng trước tiên bạn cần tạo hình ảnh vùng chứa (được xác định trong Dockerfile). Bạn có thể dùng Google Cloud Build để tạo hình ảnh vùng chứa rồi lưu trữ vào Google Container Registry.
Chuyển đến thư mục:
cd services/collage/nodejs
Phiên bản:
export SERVICE_SRC=collage
export SERVICE_NAME=${SERVICE_SRC}-service
gcloud builds submit \
. \
--tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}
Sau một hoặc hai phút, bản dựng sẽ thành công và vùng chứa sẽ được triển khai vào Google Container Registry.
Triển khai lên Cloud Run
Đặt một số biến và cấu hình cần thiết:
export BUCKET_THUMBNAILS=thumbnails-${GOOGLE_CLOUD_PROJECT}
export REGION=europe-west1
gcloud config set run/region ${REGION}
gcloud config set run/platform managed
Triển khai:
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}
Sau khi triển khai dịch vụ, bạn có thể kiểm tra xem cả hai dịch vụ có đang chạy trong phần Cloud Run của Cloud Console hay không và bước collageCall của Workflows sẽ có thể gọi dịch vụ này:

12. Triển khai quy trình công việc
Chúng tôi đã triển khai tất cả các phần phụ thuộc bên ngoài của quy trình công việc. Tất cả các bước còn lại (finalizeCompleted, pictureGarbageCollectionGCS, pictureGarbageCollectionFirestore, deleteCompleted) đều có thể được hoàn tất bằng chính Workflows.
Đã đến lúc triển khai quy trình công việc!
Chuyển đến thư mục chứa tệp workflows.yaml rồi triển khai tệp đó bằng cách:
export WORKFLOW_REGION=europe-west4
export WORKFLOW_NAME=picadaily-workflows
gcloud workflows deploy ${WORKFLOW_NAME} \
--source=workflows.yaml \
--location=${WORKFLOW_REGION}
Sau vài giây, quy trình công việc sẽ triển khai và bạn có thể thấy quy trình đó trong phần Quy trình công việc của Cloud Console:

Bạn có thể nhấp vào Quy trình công việc và chỉnh sửa quy trình đó nếu muốn. Trong quá trình chỉnh sửa, bạn sẽ thấy một bản trình bày trực quan về Quy trình công việc:

Bạn cũng có thể thực thi Quy trình công việc từ Cloud Console theo cách thủ công bằng các tham số phù hợp. Thay vào đó, chúng ta sẽ tự động thực thi hàm này để phản hồi các sự kiện Cloud Storage ở bước tiếp theo.
13. Điều kiện kích hoạt quy trình công việc (Cloud Functions)
Quy trình công việc đã được triển khai và sẵn sàng. Bây giờ, chúng ta cần kích hoạt quy trình công việc khi một tệp được tạo hoặc xoá trong bộ chứa Cloud Storage. Đây lần lượt là các sự kiện storage.object.finalize và storage.object.delete.
Workflows có API và thư viện ứng dụng để tạo, quản lý và thực thi Workflows mà bạn có thể sử dụng. Trong trường hợp này, bạn sẽ sử dụng Workflows Execution API và cụ thể hơn là thư viện ứng dụng Node.js để kích hoạt Quy trình công việc.
Bạn sẽ kích hoạt quy trình từ Cloud Functions để theo dõi các sự kiện Cloud Storage. Vì Cloud Functions chỉ có thể theo dõi một loại sự kiện, nên bạn sẽ triển khai 2 Cloud Functions để theo dõi cả sự kiện tạo và xoá:

Khám phá mã
Cloud Function này có tên là trigger-workflow. Bạn có thể kiểm tra toàn bộ mã của nó trong index.js.
Triển khai lên Cloud Functions
Chuyển đến thư mục:
cd workflows/functions/trigger-workflow/nodejs
Đặt một số biến và cấu hình cần thiết:
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}
Triển khai hàm phản hồi để hoàn tất các sự kiện:
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}
Triển khai hàm thứ hai để phản hồi các sự kiện xoá:
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}
Khi quá trình triển khai hoàn tất, bạn có thể thấy cả hai hàm trong Cloud Console:

14. Giao diện người dùng (App Engine)
Trong bước này, bạn sẽ tạo một giao diện người dùng web trên Google App Engine từ Pic-a-daily: Lab 4 – Create a web frontend (Pic-a-daily: Phòng thí nghiệm 4 – Tạo giao diện người dùng web). Giao diện này sẽ cho phép người dùng tải ảnh lên từ ứng dụng web, cũng như duyệt xem ảnh đã tải lên và hình thu nhỏ của ảnh.

Bạn có thể tìm hiểu thêm về App Engine và đọc nội dung mô tả mã trong Pic-a-daily: Lab 4 – Create a web frontend (Pic-a-daily: Bài tập 4 – Tạo giao diện người dùng web).
Khám phá mã
Ứng dụng App Engine có tên là frontend. Bạn có thể kiểm tra toàn bộ mã của nó trong index.js.
Triển khai cho App Engine
Chuyển đến thư mục:
cd frontend
Đặt khu vực bạn chọn, đồng thời thay thế GOOGLE_CLOUD_PROJECT trong app.yaml bằng mã dự án thực tế của bạn:
export REGION=europe-west1
gcloud config set compute/region ${REGION}
sed -i -e "s/GOOGLE_CLOUD_PROJECT/${GOOGLE_CLOUD_PROJECT}/" app.yaml
Triển khai:
gcloud app deploy app.yaml -q
Sau một hoặc hai phút, bạn sẽ nhận được thông báo rằng ứng dụng đang phân phát lưu lượng truy cập:
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
Bạn cũng có thể truy cập vào phần App Engine của Cloud Console để xem ứng dụng đã được triển khai hay chưa và khám phá các tính năng của App Engine như phân chia lưu lượng truy cập và quản lý phiên bản:

15. Kiểm thử quy trình công việc
Để kiểm thử, hãy chuyển đến URL App Engine mặc định cho ứng dụng (https://<YOUR_PROJECT_ID>.appspot.com/) và bạn sẽ thấy giao diện người dùng hoạt động!

Tải ảnh lên. Thao tác này sẽ kích hoạt quy trình và bạn có thể thấy quá trình thực thi quy trình ở trạng thái Active trong Cloud Console:

Sau khi quy trình hoàn tất, bạn có thể nhấp vào mã thực thi và xem đầu ra từ các dịch vụ khác nhau:

Tải thêm 3 bức ảnh lên. Bạn cũng sẽ thấy hình thu nhỏ và ảnh ghép của các hình ảnh trong bộ chứa Cloud Storage và giao diện người dùng App Engine được cập nhật:

16. Dọn dẹp (Không bắt buộc)
Nếu không có ý định giữ lại ứng dụng này, bạn có thể dọn dẹp tài nguyên để tiết kiệm chi phí và trở thành một người dùng đám mây có trách nhiệm bằng cách xoá toàn bộ dự án:
gcloud projects delete ${GOOGLE_CLOUD_PROJECT}
17. Xin chúc mừng!
Bạn đã tạo một phiên bản phối hợp của ứng dụng bằng cách sử dụng Quy trình công việc để điều phối và gọi các dịch vụ.
Nội dung đã đề cập
- App Engine
- Cloud Firestore
- Cloud Functions
- Cloud Run
- Quy trình công việc