使用回呼和 Google 試算表暫停及繼續工作流程


Google 試算表是雲端試算表解決方案,支援即時協作,並提供可視化、處理及傳達資料的工具。

本教學課程將示範如何建立及部署工作流程,以便建立回呼端點 (或 webhook)、將回呼網址儲存到 Google 試算表、暫停執行,然後等待人工核准,透過試算表重新啟動工作流程。進一步瞭解如何使用回呼功能

目標

在這個教學課程中,您將執行下列操作:

  1. 在 Google 雲端硬碟中建立新資料夾。這個資料夾用於儲存試算表,並允許工作流程寫入試算表。
  2. 建立 Google 試算表試算表,以便擷取核准結果,並啟動工作流程的回呼。
  3. 使用 Google Apps Script,這項雲端式 JavaScript 平台可讓您以程式設計方式建立、讀取及編輯 Google Workspace 產品,只要透過試算表更新核准要求,即可觸發暫停的工作流程。
  4. 建立及部署會呼叫 Google 試算表 API 連接器的工作流程,將資料附加到試算表中。當回呼透過試算表獲得核准時,工作流程會執行、暫停,然後恢復。進一步瞭解 Workflows 連接器
  5. 測試整個流程,確認工作流程是否如預期進行。

費用

In this document, you use the following billable components of Google Cloud:

To generate a cost estimate based on your projected usage, use the pricing calculator. New Google Cloud users might be eligible for a free trial.

本教學課程也使用 Google Workspace。企業級服務不在 Google 免費版消費者應用程式中提供,因此需要付費。

事前準備

您可以在 Google Cloud 控制台中執行下列部分指令,也可以在終端機或 Cloud Shell 中使用 Google Cloud CLI。

貴機構定義的安全性限制,可能會導致您無法完成下列步驟。如需疑難排解資訊,請參閱「在受限的 Google Cloud 環境中開發應用程式」。

主控台gcloud
  1. 在 Google Cloud 主控台的專案選擇器頁面中,選取或建立 Google Cloud 專案

    前往專案選取器

  2. 請確認您已為 Google Cloud 專案啟用計費功能。瞭解如何檢查專案是否已啟用計費功能

  3. 啟用 Compute Engine、Sheets 和 Workflows API。

    啟用 API

  4. 請記下 Compute Engine 預設服務帳戶,因為您會將其與本教學課程中的工作流程建立關聯,以便進行測試。啟用 Compute Engine API 的新專案會透過 IAM 基本編輯者角色建立這個服務帳戶,電子郵件格式如下:

    PROJECT_NUMBER-compute@developer.gserviceaccount.com

    您可以在 Google Cloud 控制台的「歡迎」頁面中找到專案編號。

    對於實際環境,我們強烈建議建立新的服務帳戶,並授予一或多個包含必要最低權限的 IAM 角色,並遵循最低權限原則。

  1. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

    At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.

  2. 請確認您已為 Google Cloud 專案啟用計費功能。瞭解如何檢查專案是否已啟用計費功能

  3. 啟用 Compute Engine、Sheets 和 Workflows API。

    gcloud services enable \
        compute.googleapis.com \
        sheets.googleapis.com \
        workflows.googleapis.com
  4. 請記下 Compute Engine 預設服務帳戶,因為您會將其與本教學課程中的工作流程建立關聯,以便進行測試。啟用 Compute Engine API 的新專案會透過 IAM 基本編輯者角色建立此服務帳戶,電子郵件格式如下:

    PROJECT_NUMBER-compute@developer.gserviceaccount.com

    您可以透過下列方式取得專案編號:

    gcloud projects describe PROJECT_ID

    對於實際環境,我們強烈建議建立新的服務帳戶,並授予一或多個包含必要最低權限的 IAM 角色,並遵循最低權限原則。

在 Google 雲端硬碟中建立新資料夾

在 Google 雲端硬碟中建立新資料夾。這個資料夾用於儲存試算表。設定共用資料夾的權限後,工作流程就能寫入試算表。

  1. 前往 drive.google.com
  2. 依序點選「新增」>「新資料夾」
  3. 輸入資料夾名稱。
  4. 按一下 [建立]。
  5. 在新的資料夾上按一下滑鼠右鍵,然後選取「共用」
  6. 新增 Compute Engine 預設服務帳戶的電子郵件地址。

    這樣服務帳戶就能存取資料夾。將服務帳戶與工作流程建立關聯後,工作流程就會取得資料夾中所有檔案的編輯權限。進一步瞭解如何共用檔案、資料夾和雲端硬碟

  7. 選取「編輯者」角色。

  8. 取消勾選「通知共用對象」核取方塊。

  9. 按一下「共用」

使用 Google 試算表建立試算表

透過 Google 試算表建立試算表時,系統會將試算表儲存在 Google 雲端硬碟中。根據預設,系統會將試算表儲存到雲端硬碟的根目錄。您無法使用 Google 試算表 API 直接在特定資料夾中建立試算表。不過,您可以使用其他方法,例如在建立試算表後將其移至特定資料夾,如本範例所示。詳情請參閱「使用 Google 雲端硬碟資料夾」。

  1. 前往 sheets.google.com

  2. 按一下「新增」圖示 Plus

    即可建立並開啟新的試算表。每份試算表都有專屬的 spreadsheetId 值,其中包含字母、數字、連字號或底線。你可以在 Google 試算表網址中找到試算表 ID:

    https://docs.google.com/spreadsheets/d/spreadsheetId/edit#gid=0

  3. 請記下這個 ID,因為您在建立工作流程時會用到。

  4. 新增欄標題,以符合下列範例:

    記錄核准作業的試算表範例

    請注意,G 欄中的值「Approved?」會用於在工作流程中啟動回呼。

  5. 將試算表移至先前建立的 Google 雲端硬碟資料夾:

    1. 在試算表中,依序選取「檔案」>「移動」
    2. 前往您建立的資料夾。
    3. 按一下 [移動]

您也可以使用 Google 試算表 API 連接器建立試算表。請注意,使用連接器時,spreadsheetId 可從 resp 結果擷取。例如:

- create_spreadsheet:
    call: googleapis.sheets.v4.spreadsheets.create
    args:
      body:
      connector_params:
        scopes: ${driveScope}
    result: resp
- assign_sheet_id:
    assign:
      - sheetId: ${resp.spreadsheetId}

使用 Apps Script 擴充 Google 試算表

您可以透過程式輔助方式,使用 Apps Script 建立、讀取及編輯 Google 試算表。大部分的試算表指令碼都會操控陣列,以便與試算表中的儲存格、列和欄互動。如要瞭解如何搭配 Google 試算表使用 Apps Script,請參閱自訂函式快速入門課程

  1. 透過 Google 試算表建立 Apps Script 專案:

    1. 開啟 Google 試算表試算表。
    2. 依序選取「擴充功能」>「Apps Script」
    3. 在指令碼編輯器中,按一下「未命名專案」
    4. 為專案命名,然後按一下「重新命名」

    指令碼現在已繫結至試算表,因此可透過特殊功能變更使用者介面,或在試算表開啟時回應。

    指令碼專案代表 Apps Script 檔案和資源的集合。指令碼專案中的程式碼檔案會使用 .gs 副檔名。

  2. 您可以使用 Apps Script 編寫自訂函式,並在 Google 試算表中使用這些函式,就像使用內建函式一樣。自訂函式是使用標準 JavaScript 建立。建立函式:

    1. 開啟 Apps Script 專案。
    2. 按一下「編輯器」圖示
    3. 指令碼檔案會顯示為名為 Code.gs 的專案檔案。如要編輯檔案,請選取該檔案。
    4. 將指令碼編輯器中的任何程式碼替換為下列程式碼,這段程式碼會讀取試算表中的資料,並將資料傳遞為工作流程執行作業的輸入內容:

      function handleEdit(e) {
        var range = e.range.getA1Notation();
        var sheet = e.source;
      
        if (range.length > 1 && range[0] === 'G') {
          if (e.value == "TRUE") {
            Logger.log("Approved: TRUE");
      
            var row = range.slice(1);
            var url = sheet.getRange('E' + row).getCell(1, 1).getValue();
            var approver = sheet.getRange('F' + row).getCell(1, 1).getValue();
      
            callback(url, approver);
          }
          else {
            Logger.log("Approved: FALSE");
          }
        }
      }
      
      function callback(url, approver) {
        const headers = {
          "Authorization": "Bearer " + ScriptApp.getOAuthToken()
        };
      
        var payload = {
          'approver': approver
        };
      
        const params = {
          "method": 'POST',
          "contentType": 'application/json',
          "headers": headers,
          "payload": JSON.stringify(payload)
        };
      
      
        Logger.log("Workflow callback request to " + url);
        var response = UrlFetchApp.fetch(url, params);
        Logger.log(response);
      }
    5. 按一下「儲存」圖示

  3. Apps Script 可安裝的觸發事件可讓指令碼專案在符合特定條件 (例如開啟或編輯試算表) 時執行指定函式。建立觸發條件:

    1. 開啟 Apps Script 專案。
    2. 按一下「觸發條件」圖示
    3. 按一下「新增觸發條件」
    4. 在「Add Trigger for YOUR_PROJECT_NAME」對話方塊中,設定觸發條件:
      1. 在「Choose which function to run」(選擇要執行的函式) 清單中,選取「handleEdit」
      2. 在「Choose which deployment should run」(選擇要執行的部署作業) 清單中,選取「Head」
      3. 在「Select event source」清單中,選取「From spreadsheet」
      4. 在「Select event type」(選取事件類型) 清單中,選取「On edit」(編輯時)。
      5. 在「失敗通知設定」清單中,選取「通知我每天一次」
    5. 按一下 [儲存]
    6. 如果系統提示您選擇 Google 帳戶,請選取適當的帳戶,然後按一下「允許」

      這樣一來,您的 Apps 指令碼專案就能查看、編輯、建立及刪除 Google 試算表試算表,以及連線至外部服務。

  4. Apps Script 專案資訊清單檔案是指指定 Apps Script 執行指令碼時所需的基本專案資訊的 JSON 檔案。請注意,Apps Script 編輯器預設會隱藏資訊清單檔案,以保護您的 Apps Script 專案設定。編輯資訊清單檔案:

    1. 開啟 Apps Script 專案。
    2. 按一下「Project Settings」圖示
    3. 勾選「在編輯器中顯示『appsscript.json』資訊清單檔案」核取方塊。
    4. 按一下「編輯器」圖示
    5. 資訊清單檔案會顯示為名為 appsscript.json 的專案檔案。選取檔案即可編輯。
    6. oauthScopes 欄位會指定字串陣列。如要設定專案使用的授權範圍,請新增要支援的範圍陣列。例如:

      {
        "timeZone": "America/Toronto",
        "dependencies": {
        },
        "exceptionLogging": "STACKDRIVER",
        "runtimeVersion": "V8",
        "oauthScopes": [
          "https://www.googleapis.com/auth/script.external_request",
          "https://www.googleapis.com/auth/cloud-platform",
          "https://www.googleapis.com/auth/spreadsheets"
        ]
      }

      這會將明確的範圍設為:

      • 連線至外部服務
      • 查看、編輯、設定及刪除您的 Google Cloud 資料,以及查看您 Google 帳戶的電子郵件地址
      • 查看、編輯、建立及刪除您的所有 Google 試算表檔案
    7. 按一下「儲存」圖示

部署寫入試算表並使用回呼的工作流程

部署工作流程,在透過試算表核准回呼時執行、暫停,然後繼續執行。工作流程會使用 Google Sheets API 連接器寫入 Sheets 試算表。

控制台gcloud
  1. 前往 Google Cloud 控制台的「Workflows」頁面:

    前往「Workflows」頁面

  2. 按一下「建立」

  3. 輸入新工作流程的名稱:workflows-awaits-callback-sheets

  4. 在「Region」(區域) 清單中,選取「us-central1 (Iowa)」(us-central1 (愛荷華州))

  5. 在「服務帳戶」中,選取 Compute Engine 預設服務帳戶 (PROJECT_NUMBER-compute@developer.gserviceaccount.com)。

  6. 點按「Next」

  7. 在工作流程編輯器中,輸入工作流程的定義:

    main:
      steps:
        - init:
            assign:
            # Replace with your sheetId and make sure the service account
            # for the workflow has write permissions to the sheet
            - sheetId: "10hieAH6b-oMeIVT_AerSLNxQck14IGhgi8ign-x2x8g"
        - before_sheets_callback:
            call: sys.log
            args:
              severity: INFO
              data: ${"Execute steps here before waiting for callback from sheets"}
        - wait_for_sheets_callback:
            call: await_callback_sheets
            args:
              sheetId: ${sheetId}
            result: await_callback_result
        - after_sheets_callback:
            call: sys.log
            args:
              severity: INFO
              data: ${"Execute steps here after receiving callback from sheets"}
        - returnResult:
            return: ${await_callback_result}
    
    await_callback_sheets:
        params: [sheetId]
        steps:
            - init:
                assign:
                  - project_id: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
                  - location: ${sys.get_env("GOOGLE_CLOUD_LOCATION")}
                  - workflow_id: ${sys.get_env("GOOGLE_CLOUD_WORKFLOW_ID")}
                  - execution_id: ${sys.get_env("GOOGLE_CLOUD_WORKFLOW_EXECUTION_ID")}
            - create_callback:
                call: events.create_callback_endpoint
                args:
                  http_callback_method: POST
                result: callback_details
            - save_callback_to_sheets:
                call: googleapis.sheets.v4.spreadsheets.values.append
                args:
                    range: ${"Sheet1!A1:G1"}
                    spreadsheetId: ${sheetId}
                    valueInputOption: RAW
                    body:
                        majorDimension: "ROWS"
                        values:
                          - ["${project_id}", "${location}", "${workflow_id}", "${execution_id}", "${callback_details.url}", "", "FALSE"]
            - log_and_await_callback:
                try:
                  steps:
                    - log_await_start:
                        call: sys.log
                        args:
                          severity: INFO
                          data: ${"Started waiting for callback from sheet " + sheetId}
                    - await_callback:
                        call: events.await_callback
                        args:
                          callback: ${callback_details}
                          timeout: 3600
                        result: callback_request
                    - log_await_stop:
                        call: sys.log
                        args:
                          severity: INFO
                          data: ${"Stopped waiting for callback from sheet " + sheetId}
                except:
                    as: e
                    steps:
                        - log_error:
                            call: sys.log
                            args:
                                severity: "ERROR"
                                text: ${"Received error " + e.message}
            - check_null_await_result:
                switch:
                  - condition: ${callback_request == null}
                    return: null
            - log_await_result:
                call: sys.log
                args:
                  severity: INFO
                  data: ${"Approved by " + callback_request.http_request.body.approver}
            - return_await_result:
                return: ${callback_request.http_request.body}
  8. 請務必將預留位置 sheetId 的值替換為 spreadsheetId

  9. 按一下 [Deploy] (部署)

  1. 建立工作流程的原始碼檔案:

    touch workflows-awaits-callback-sheets.yaml
  2. 在文字編輯器中,將下列工作流程複製到原始碼檔案:

    main:
      steps:
        - init:
            assign:
            # Replace with your sheetId and make sure the service account
            # for the workflow has write permissions to the sheet
            - sheetId: "10hieAH6b-oMeIVT_AerSLNxQck14IGhgi8ign-x2x8g"
        - before_sheets_callback:
            call: sys.log
            args:
              severity: INFO
              data: ${"Execute steps here before waiting for callback from sheets"}
        - wait_for_sheets_callback:
            call: await_callback_sheets
            args:
              sheetId: ${sheetId}
            result: await_callback_result
        - after_sheets_callback:
            call: sys.log
            args:
              severity: INFO
              data: ${"Execute steps here after receiving callback from sheets"}
        - returnResult:
            return: ${await_callback_result}
    
    await_callback_sheets:
        params: [sheetId]
        steps:
            - init:
                assign:
                  - project_id: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
                  - location: ${sys.get_env("GOOGLE_CLOUD_LOCATION")}
                  - workflow_id: ${sys.get_env("GOOGLE_CLOUD_WORKFLOW_ID")}
                  - execution_id: ${sys.get_env("GOOGLE_CLOUD_WORKFLOW_EXECUTION_ID")}
            - create_callback:
                call: events.create_callback_endpoint
                args:
                  http_callback_method: POST
                result: callback_details
            - save_callback_to_sheets:
                call: googleapis.sheets.v4.spreadsheets.values.append
                args:
                    range: ${"Sheet1!A1:G1"}
                    spreadsheetId: ${sheetId}
                    valueInputOption: RAW
                    body:
                        majorDimension: "ROWS"
                        values:
                          - ["${project_id}", "${location}", "${workflow_id}", "${execution_id}", "${callback_details.url}", "", "FALSE"]
            - log_and_await_callback:
                try:
                  steps:
                    - log_await_start:
                        call: sys.log
                        args:
                          severity: INFO
                          data: ${"Started waiting for callback from sheet " + sheetId}
                    - await_callback:
                        call: events.await_callback
                        args:
                          callback: ${callback_details}
                          timeout: 3600
                        result: callback_request
                    - log_await_stop:
                        call: sys.log
                        args:
                          severity: INFO
                          data: ${"Stopped waiting for callback from sheet " + sheetId}
                except:
                    as: e
                    steps:
                        - log_error:
                            call: sys.log
                            args:
                                severity: "ERROR"
                                text: ${"Received error " + e.message}
            - check_null_await_result:
                switch:
                  - condition: ${callback_request == null}
                    return: null
            - log_await_result:
                call: sys.log
                args:
                  severity: INFO
                  data: ${"Approved by " + callback_request.http_request.body.approver}
            - return_await_result:
                return: ${callback_request.http_request.body}
  3. 請務必將預留位置 sheetId 的值替換為 spreadsheetId

  4. 輸入下列指令來部署工作流程:

    gcloud workflows deploy workflows-awaits-callback-sheets \
        --source=workflows-awaits-callback-sheets.yaml \
        --location=us-central1 \
        --service-account=PROJECT_NUMBER-compute@developer.gserviceaccount.com

    PROJECT_NUMBER 替換為您的 Google Cloud專案編號。您可以透過下列方式取得專案編號:

    gcloud projects describe PROJECT_ID

測試端對端流程

執行工作流程,測試端對端流程。執行工作流程會執行與工作流程相關聯的目前工作流程定義。

控制台gcloud
  1. 前往 Google Cloud 控制台的「Workflows」頁面:

    前往「Workflows」頁面

  2. 在「Workflows」頁面中,選取「workflows-awaits-callback-sheets」工作流程,前往該工作流程的詳細資料頁面。

  3. 在「Workflow details」(工作流程詳細資料)頁面中,按一下 「Execute」(執行)

  4. 再次按一下「執行」

    工作流程會開始執行,執行狀態應為「Running」。記錄檔也會指出工作流程已暫停並等待:

    Execute steps here before waiting for callback from sheets
    ...
    Started waiting for callback from sheet 1JlNFFnqs760M_KDqeeeDc_qtrABZDxoalyCmRE39dpM
  5. 確認工作流程已將回呼詳細資料寫入試算表中的一列。

    舉例來說,您應該會在「執行 ID」欄中看到工作流程執行 ID,在「回呼網址」欄中看到回呼端點,以及在「已核准?」欄中看到「FALSE」

  6. 在試算表中,將「FALSE」變更為「TRUE」

    一兩分鐘後,執行作業應會恢復,並以「Succeeded」的執行狀態完成。

  1. 開啟終端機。

  2. 執行工作流程:

      gcloud workflows run workflows-awaits-callback-sheets

    工作流程會開始,輸出內容應會指出工作流程已暫停並等待:

      Waiting for execution [a8361789-90e0-467f-8bd7-ea1c81977820] to complete...working.

  3. 確認工作流程已將回呼詳細資料寫入試算表中的一行。

    舉例來說,您應該會在「執行 ID」欄中看到工作流程執行 ID,在「回呼網址」欄中看到回呼端點,以及在「已核准?」欄中看到「FALSE」

  4. 在試算表中,將「FALSE」變更為「TRUE」

    一兩分鐘後,執行作業應會恢復,然後以 SUCCEEDED 的執行狀態完成。

清除所用資源

如果您是為了這個教學課程建立新專案,請刪除專案。如果您使用現有的專案,且希望保留該專案而不採用本教學課程中新增的變更,請刪除為教學課程建立的資源

刪除專案

如要避免付費,最簡單的方法就是刪除您為了本教學課程所建立的專案。

如要刪除專案:

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

刪除本教學課程中建立的資源

  1. 刪除 Google 雲端硬碟中的檔案
  2. 刪除工作流程

後續步驟